目录
2.共享数据的所有访问都必须作为临界区,使用synchronized加锁
4.如果一个方法的整个方法都在synchronized中,则可以把关键字放在函数声明中
Java中对共享数据操作的并发控制采用了传统的锁技术。
一个程序中单独的、并发的线程对同一对象进行访问的代码段被称为临界区。
使用synchronized关键字标识,临界区可以是一个语句块,或方法。
synchronized (object) 被称为对象锁,给object对象上锁。是独占排它锁,其他线程不能对该对象操作。
对象锁使用说明:
1.返回对象的锁
对象的锁在如下几种情况下由持有线程返还
- synchronized()语句执行完毕
- synchronized()语句中出现异常
- 当持有锁的线程调用该对象的wait()方法,释放对象锁,被放入对象的wait pool
2.共享数据的所有访问都必须作为临界区,使用synchronized加锁
3.synchronized保护的共享数据必须是私有的
4.如果一个方法的整个方法都在synchronized中,则可以把关键字放在函数声明中
5.对象锁具有可重入性
死锁的防治
多个线程相互等待对方持有的锁,但是对方的锁都不释放,就造成了死锁。
获取锁的顺序 需要全局考虑,释放锁的顺序和加锁顺序相反。
线程之间的交互:wait() , notify()
线程中调用了某对象的X.wai() ,该线程将被放入X的wait pool中,该线程将释放X的锁;
当调用X.notify() X中的wait pool中一个线程将被移入lock pool,并等待X的锁;
notifyAll() 把X的wait pool中的所有线程都放入lock pool;
临界区代码
import java.util.Vector;
public class SyncStack {
private Vector buffer = new Vector(400,200);
public synchronized char pop(){
char c;
while(buffer.size()==0){
try{
this.wait();
}catch (InterruptedException e){
e.printStackTrace();
}
}
c = ((Character) buffer.remove(buffer.size() - 1)).charValue();
return c;
}
public synchronized void push(char c){
this.notify();
Character charObj = new Character(c);
buffer.addElement(charObj);
}
}
不建议使用:
stop :强制终止进程,容易造成数据不一致
suspend() 和resum():suspend暂停线程但是不会释放锁,容易造成死锁。
线程运行状态
新建、可运行状态(就绪)、运行、阻塞(等待)、结束。
- 新建: 使用Thread类或其子类创建的线程,还未分配相关资源,只能使用start 和stop 方法;
- 可运行状态:使用start方法后,将线程由新建变为可运行太,并分配资源,等待调度;
- 运行态:线程占用CPU执行,状态变迁由三种:
- 1. 正常执行后到结束
- 2.被高优先级抢占式夺取CPU,或者时间片使用完而进入就绪(Runnable);
- 3.进入阻塞态
- 线程调用了sleep(),join(),wait()方法
- 使用synchronized 来请求对象的锁而为获得时
- 线程中由输入输出操作
- 阻塞状态(block):
- sleep() join() 是等待阻塞
- wait(), notify(),notifyAll(),synchronized 唤醒,被中断interrupt或等待时间到,是对象锁阻塞
- 终止状态(Dead)
支持线程的类
均在lang包下
Thread
thread 的子类实现run() {} 方法中的线程体
Runnable
实现了Runnable接口的类中的run方法提供线程体
Object类
wait(), notify(),notifyAll()
ThreadGroup类
ThreadDeath类
线程组
package Thread03;
public class TestMain {
public static void main(String[] args) {
ThreadGroup mySchool = new ThreadGroup("mySchool");
Thread t1 = new Thread(mySchool, new Sing());
Thread t2 = new Thread(mySchool, new Dance());
System.out.println("唱歌线程组:" + t1.getThreadGroup());
System.out.println("跳舞线程组:" + t2.getThreadGroup());
t1.start();
t2.start();
t1.setName("唱歌");
System.out.println("线程唱歌名字:" + t1.getName());
System.out.println(t2.toString());
}
}
class Sing extends Thread{
@Override
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println("im sing............");
}
}
}
class Dance implements Runnable{
@Override
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println("im danceing......................");
}
}
}
Thread类其他的方法
setName() ,getName() 设置线程名,获取线程名
activeCount() 返回线程组中活动线程的个数
getThreadGroup() 获取线程组
setDaemon() 设置守护线程
isDaemon()判断是否为守护线程
toString()返回线程id,优先级,线程组