java多线程学习记录

  • “Thread extends Object implements Runnable”

  • 继承 Extend Thread,重写run方法

public class ExtThread2 extends Thread {
    private int count = 1;
    @Override
    public void run() {
    }
}

  Thread th1 = new ExtThread2("name");
  th1.start();
  • 实现implements Runnable,实现run方法,创建实例作为Thread构造器的参数;用同一个Runnable实例创建Thread时,可以共享同一个变量。
public class ExtThread1 implements Runnable {
    private int count = 1;
    public void run() {}
}

Runnable my = new ExtThread1();
Thread th1 = new Thread(my,"name");
th1.start();
  • Callable接口定义了call()方法,Future接口定义了几个方法来控制关联的Callable任务;Future的实现类Futuretask既实现了Future,也实现了Runnable
// 该接口有泛型限制,与返回值类型相同
public class CallThread implements Callable<Integer>{
    public Integer call() {return }
}
Callable th3 = new CallThread();
FutureTask task = new FutureTask(th3);
// 因为FutureTask实现了Runnable,所以可以传递给Thread
new Thread(task,"callableThread").start();
try{
// 同时还可以利用Future来监控任务的执行情况
// 如果只开启了一个线程,然后就使用get则,后面的线程要等待该线程执行完才会继续向下执行
// 为了避免阻塞,可以先把所有的线程启动,然后再获取对应的结果,这样就不会阻塞
    System.out.println(task.get());
} catch (Exception e) {
    e.printStackTrace();
}

总结:创建线程的三种方式对比

Runnable/Callable
- 线程类还可以继承其他类
- 多个线程可以共享同一个target对象
- Callable还有返回值

线程的生命周期

  • 新建(new)、就绪(runnable)、运行(running)、阻塞(blocked)、死亡(Dead)
  • join线程:在一个线程里面调用另外一个线程,并等待其执行完毕
  • daemon后台线程:前台线程死亡后,JVM会通知后台线程死亡
  • sleep:暂停当前正在执行的线程,一直阻塞到指定时间,然后线程才变成就绪状态(其他线程继续)
  • yield:也是暂停线程,但是会把线程转变成就绪状态(不阻塞),所以线程可能随时有被调度,这种不保险,没有意义。

线程同步

  • synchronized用来修饰方法、代码块(对this对象,或者普通的对象进行监视)(加锁–放锁)
  • notify/notifyAll/wait用于在synchronized代码块中线程间的通信
  • notify用于唤醒该同步监视器上的线程。说明:“只是唤醒wait的线程,当前线程会继续执行下去,被唤醒的线程也不一定是立马就执行”;被唤醒的线程执行的时候,是在wait处继续向下执行,不是重新执行;被唤醒后就可以抢占资源了;从上面可以看出,notify必须和wait搭配使用才有意义
  • wait用于将当前线程阻塞,但需要把占用的锁先释放掉,只有被重新唤醒才会继续执行,否则会一直阻塞;sleep同样会阻塞,但只会阻塞固定的时间,而且阻塞的时候会继续占用锁。

你可能感兴趣的:(java,多线程,java)