🚩 Home / java / thread.md

多线程

继承Thread实现多线程

实现run()方法,即线程的执行主体在run()方法之中,调用的时候通过start()方法调用。

class MyThread extends Thread {
    private String name;
    public MyThread(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(this.name + " - " + i);
        }
    }
}

public class MainTest {

    public static void main(String[] args) {
        new MyThread("thread1").start();
        new MyThread("thread2").start();
        new MyThread("thread3").start();
    }
}
  • 每个线程同时只能调用一次,同时调用多次发生 IllegalThreadStateException.

基于Runnable接口实现多线程

class MyThread implements Runnable {
    private String name;
    public MyThread(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(this.name + " - " + i);
        }
    }
}

public class MainTest {

    public static void main(String[] args) {
        Thread t1 = new Thread(new MyThread("Thread1"));
        Thread t2 = new Thread(new MyThread("Thread2"));
        t1.start();
        t2.start();
    }
}

即将一个任务放在一个实现Runnable的类中(即run方法中),然后通过Thread的start()方法调用。同一个核心业务可以被多个线程调用。即多个线程可用访问同一个资源。

jdk1.8以后可用使用lambda表达式来编写。

public class MainTest {

    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                System.out.println("Thread2" + " - " + i);
            } 
        });
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                System.out.println("Thread1" + " - " + i);
            }
        });
        t1.start();
        t2.start();
    }
}

即Thread和Runnable更像是一个代理模式的设计,Thread负责执行,runnable负责产生一个任务。

Callable实现多线程

Runnable的缺点就是没有返回值。

Callable定义:

public interface Callable<V> {
    public V call() throws Exception;
}

Callable可以设置一个泛型作为返回值的类型。

class MyThread implements Callable<String> {
    @Override
    public String call() throws Exception {
        for (int i = 0; i < 10; i++) {
            System.out.println("*******执行i:" +i );
        }
        return "执行完毕";
    }
}
public class MainTest {

    public static void main(String[] args) throws Exception{
        FutureTask<String> task = new FutureTask<>(new MyThread());
        new Thread(task).start();
        System.out.println(task.get());
    }
}

多线程操作:

  • 线程命名与取得

对于线程,可用对线程设置一个名字,这样可用为线程附上一个唯一标识.

class MyThread implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}
public class MainTest {
    public static void main(String[] args) throws Exception{
        new Thread(new MyThread(), "T1").start();
        new Thread(new MyThread(), "T2").start();
        System.out.println(Thread.currentThread().getName());
    }
}
  • 线程休眠

使用Thread.sleep()方法。

  • 线程中断

在线程休眠的过程中可用使用 interrupt()方法来打断线程休眠

public class MainTest {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            System.out.println("begin to sleep");
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                System.out.println("interrupted");
            }
            System.out.println("end sleep");
        });
        thread.start();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {

        }
        if (!thread.isInterrupted()) {
            thread.interrupt();
        }
    }
}
  • 线程强制执行

线程独占资源,一直执行到结束

使用join()方法,这个方法是等待线程死亡,所以如下代码,当x == 10时,T1线程会先等待主线程执行完之后才会再执行。倘如是Thread.currentThread().join()那么就是T1线程等待T1执行完才执行,这样就会产生矛盾,导致T1线程无法执行完。

public class MainTest {
    public static void main(String[] args) {
        Thread mainThread = Thread.currentThread();
        Thread thread = new Thread(() -> {
            for (int x = 0; x < 100; x++) {
                if (x == 10) {
                    try {
                        mainThread.join();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                System.out.println(Thread.currentThread().getName() + " x = " + x);
            }
        }, "T1");
        thread.start();

        for (int x = 0; x < 100; x++) {
            System.out.println("main" + " x = " + x);
        }

    }
}
  • 线程礼让

使用yield()方法。该方法就是当前线程让出cpu资源。

public class MainTest {
    public static void main(String[] args) {
        Thread mainThread = Thread.currentThread();
        Thread thread = new Thread(() -> {
            for (int x = 0; x < 100; x++) {
                if (x % 3 == 0) {
                    Thread.yield();
                }
                System.out.println(Thread.currentThread().getName() + " x = " + x);
            }
        }, "T1");
        thread.start();

        for (int x = 0; x < 100; x++) {
            System.out.println("main" + " x = " + x);
        }

    }
}
  • 线程优先级

Thread.MAX_PRIORITY — 10

Thread.NORM_PRIORITY — 5

Thread.MIN_PRIORITY — 1

主线程优先级是5,getPriority()方法获取优先级

public class MainTest {
    public static void main(String[] args) {
        Runnable runnable = () -> {
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName() + " i = " + i);
            }
        };
        Thread t1 = new Thread(runnable, "T1");
        Thread t2 = new Thread(runnable, "T2");
        Thread t3 = new Thread(runnable, "T3");
        t1.setPriority(Thread.MAX_PRIORITY); // 10
        t2.setPriority(Thread.NORM_PRIORITY);// 5
        t3.setPriority(Thread.MIN_PRIORITY); // 1
        t1.start();
        t2.start();
        t3.start();
    }
}

线程同步

java中要进行线程同步,需要使用synchronized关键字来声明一个代码块或函数,指明每次只能有一个线程来访问。

class MyRun implements Runnable {
    private int ticket = 10;

    public synchronized boolean sale() {
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        if (ticket > 0) {
            System.out.println(Thread.currentThread().getName() + " 卖票,还剩" + --ticket + "张");
            return true;
        } else {
            return false;
        }
    }

    @Override
    public void run() {
        while(sale());
    }
}
public class MainTest {
    public static void main(String[] args) {
        MyRun run = new MyRun();
        new Thread(run, "T1").start();
        new Thread(run, "T2").start();
        new Thread(run, "T3").start();
    }
}

或写在代码块:

class MyRun implements Runnable {
    private int ticket = 10;

    @Override
    public void run() {
        while (true) {
            synchronized (this) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                if (ticket > 0) {
                    System.out.println(Thread.currentThread().getName() + " 卖票,还剩" + --ticket + "张");
                } else {
                    break;
                }
            }
        }
    }
}

线程等待与唤醒

  • wait()方法,等待即挂起,没有唤醒就一直等待。针对当前线程。

  • notify()方法,唤起第一个等待的线程。notifyAll()唤起所有等待线程。

    class Message {

      private String title;
      private String content;
      private boolean flag = true;
    
      public synchronized void set(String title, String content) {
          if (flag == false) {
              try {
                  super.wait();
              } catch (InterruptedException e) {
                  // TODO Auto-generated catch block
                  e.printStackTrace();
              }
          }
    
          this.title = title;
          try {
              Thread.sleep(100);
          } catch (Exception e) {
              // TODO: handle exception
          }
          this.content = content;
          this.flag = false;
          super.notify();
      }
    
      public synchronized String get() {
          if (flag == true) {
              try {
                  super.wait();
              } catch (InterruptedException e) {
                  // TODO: handle exception
              }
          }
    
          try {
              Thread.sleep(10);
          } catch (Exception e) {
              // TODO: handle exception
          }
          this.flag = true;
          super.notify();
    
          return this.title + " - " + this.content;
      }

    }

    public class MainTest {

      public static void main(String[] args) {
          Message message = new Message();
          new Thread(new Producer(message)).start();
          new Thread(new Consumer(message)).start();
      }

    }

    class Producer implements Runnable {

      private Message message;
      public Producer(Message message) {
          this.message = message;
      }
    
      @Override
      public void run() {
          // TODO Auto-generated method stub
          for (int x = 0; x < 100; x++) {
              if (x % 2 == 0) {
                  this.message.set("A", "aaa");
              } else {
                  this.message.set("B", "bbb");
              }
          }
      }

    }

    class Consumer implements Runnable {

      private Message message;
      public Consumer(Message msg) {
          this.message = msg;
      }
      @Override
      public void run() {
          // TODO Auto-generated method stub
          for (int x = 0; x < 100; x++) {
              System.out.println(x + this.message.get());
          }
      }

    }

守护线程

setDaemon()方法实现设置线程为守护线程,即让线程在其他线程终止之后会停掉。

public class MainTest {
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            for (int x = 0; x < 10; x ++) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + x);
            }
        }, "T");
        Thread t2 = new Thread(() -> {
            for (int x = 0; x < Integer.MAX_VALUE; x ++) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + x);
            }
        }, "守护线程");
        t2.setDaemon(true);
        t1.start();
        t2.start();
    }
}

volatile

直接对内存中的数据进行操作。即能够比较快速的操作内存数据。不经过拷贝。