Java多线程编程2
Thread类
Thread类综合了Java程序中一个线程需要拥有的属性和方法,其构造方法如下:
public Thread();
public Thread (ThreadGroup group,Runnable target,String name);
public Thread(Runnable target);
public Thread(Runnable target,String name);
public Thread(String name);
public Thread(ThreadGroup group,Runnable target);
public Thread(ThreadGroup group,String name);
- 继承Thread类实现多线程
需要重写run方法实现线程的任务.需要注意的是,程序中不要直接调用此方法,而是调用线程对象的start()方法启动线程,让其进入可调度状态,线程获得调度自动执行run()方法. - 实现Runnable接口编写多线程
通过 Thread 类的构造函数public Thread(Runnable target)可以将一个Runnable 接口对象传递给线程,线程在调度时将自动调用Runnable 接口对象的run方法。
使用线程
若想有效使用多线程代码,要对监视器和锁有些基本的认识。你需要知道的要点如下。
• 同步是为了保护对象的状态和内存,而不是代码。
• 同步是线程间的协助机制。一个缺陷就可能破坏这种协助模型,导致严重的后果。
• 获取监视器只能避免其他线程再次获取这个监视器,而不能保护对象。
• 即便对象的监视器锁定了,不同步的方法也能看到(和修改)不一致的状态。
• 锁定 Object[] 不会锁定其中的单个对象。
• 基本类型的值不可变,因此不能(也无需)锁定。
• 接口中声明的方法不能使用 synchronized 修饰。
• 内部类只是语法糖,因此内部类的锁对外层类无效(反过来亦然)。
• Java 的锁可重入(reentrant)。这意味着,如果一个线程拥有一个监视器,这个线程遇到具有同一个监视器的同步代码块时,可以进入这个代码块。
wait() 和 notify() 方法必须在 synchronized 修饰的方法或代码块中使用,
因为只有临时把锁放弃,这两个方法才能正常工作。
线程调度与优先级(多线程的特性: 随机性)
Java采用抢占式调度策略,下面几种情况下,当前线程会放弃CPU:
- 当前时间片用完;
- 线程在执行时调用了
yield()
或sleep()
方法主动放弃; - 进行I/O 访问,等待用户输入,导致线程阻塞;或者为等候一个条件变量,线程调用
wait
方法; - 有高优先级的线程参与调度。
- 线程的优先级用数字来表示,范围从1~10。主线程的默认优先级为5
//三个常用的优先级
Thread.MIN_PRIORITY=1
Thread.NORM_PRIORITY=5
Thread.MAX_PRIORITY=10
线程资源的同步处理
临界资源问题
Java对于多线程的安全问题提供了专业的解决方式: 就是同步代码块
synchronized(对象) {
需要被同步的代码
}
- 对象如同锁,持有锁的线程可以在同步中执行.
- 没有持有锁的线程及时获取cpu的执行权,也进不去,因为没有获取锁.
同步的前提:
- 必须要有两个或者以上的线程
- 必须要多个线程使用同一个锁
好处:解决了多线程的安全问题
弊端:多个线程需要判断锁,较为消耗资源.
同步函数使用的是哪个锁:
函数需要被对象调用,那么函数都有一个所属对象的引用.就是this. 所以同步函数使用的锁是this锁.静态函数使用的是该方法所在类的字节码文件对象.
避免死锁
多个线程相互等待对方释放持有的锁,并且在得到对方锁之前不释放自己的锁.(自己能写一个死锁代码)