1.线程的同步
1)The code segments within a program that access the same object from separate, concurrent threads are called “critical sections”。这是临界区的概念。
2)同步的两种方式:同步块和同步方法。
3)每一个对象都有一个监视器,或者叫做锁。
当线程执行到synchronized的时候,检查传入的实参对象,并得到该对象的锁旗标。如果得不到,那么此线程就会被加入到一个与该对象的锁旗标相关联的等待线程池中,一直等到对象的锁旗标被归还,池中的等待线程就会得到该锁旗标,然后继续执行下去。当线程执行完成同步代码块,就会自动释放它占有的同步对象的锁旗标。一个用于synchronized语句中的对象称为监视器,当一个线程获得了synchronized(object)语句中的代码块的执行权,即意味着它锁定了监视器。
4)同步方法利用的是this所代表的对象的锁。
下面实例介绍代码块与方法间的同步。观察this的作用。
public class ThreadDemo6 {
public static void main(String[] args) {
ThreadTest t = new ThreadTest();
new Thread(t).start();
try {
Thread.sleep(1);//(1)
} catch (InterruptedException e) {
e.printStackTrace();
}
t.str=new String("method");
new Thread(t).start();
}
}
class ThreadTest implements Runnable {
private int tickets = 100;
private int flag=0;
String str = new String("");
public void run() {
if (str.equals("method")) {
while (flag==0) {
sale();
}
} else {
while (true) {
synchronized (this) {//synchronized (str)//(2)
if (tickets > 0) {
try {
Thread.sleep(10);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ " is saling ticket " + tickets--);
} else return;
}
}
}
}
public synchronized void sale() {
if (tickets > 0) {
try {
Thread.sleep(10);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("track in method sale.");
System.out.println(Thread.currentThread().getName()
+ " is saling ticket " + tickets--);
} else flag = 1;
}
}注1,如果不使主线程sleep,很可能两个新建线程都执行同步方法(sale)中的代码。因为,产生并启动第一个线程,这个线程不见得马上开始运行,CPU可能还在原来的main线程上运行,并将str变量设置为”method”,等到第一个线程真正开始运行时,此刻检查到str的值为”method”,所以它将运行sale方法。
注2,如果使用synchronized (str),则两个线程不会同步。
5)要时刻考虑CPU会随时切换线程的情况。
6)同步是以牺牲程序的性能为代价的。
1.1同步代码块
ThreadDemo2.java
class ThreadTest implements Runnable {
private int tickets = 100;
String str = new String("");
public void run() {
while (true) {
synchronized (str) {
if (tickets > 0) {
try {
Thread.sleep(10);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ " is saling ticket " + tickets--);
} else return;
}
}
}
}
public class ThreadDemo2 {
public static void main(String[] args){
ThreadTest t=new ThreadTest();
new Thread(t).start();
new Thread(t).start();
new Thread(t).start();
new Thread(t).start();
}
}
1.2同步方法
ThreadDemo3.java
class ThreadTest implements Runnable {
private int tickets = 100;
private int flag=0;
public void run() {
while (flag==0) sale();
}
public synchronized void sale() {
if (tickets > 0) {
try {
Thread.sleep(10);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ " is saling ticket " + tickets--);
}else flag=1;
}
}
public class ThreadDemo3 {
public static void main(String[] args){
ThreadTest t=new ThreadTest();
new Thread(t).start();
new Thread(t).start();
new Thread(t).start();
new Thread(t).start();
}
}在同一个类中,使用synchronized关键字定义的若干方法,可以在多个线程之间同步,当有一个线程进入了synchronized修饰的方法(获得监视器),其他线程就不能进入同一个对象的所有使用了synchronized修饰的方法,直到第一个线程执行完它所进入的synchronized修饰的方法为止(离开监视器)。
死锁是一个经典的多线程问题,因为不同的线程都在等待那些根本不可能被释放的锁,从而导致所有的工作都无法完成。假设有两个线程,分别代表两个饥饿的人,他们必须共享刀叉并轮流吃饭。他们都需要获得两个锁:共享刀和共享叉的锁。假如线程 "A" 获得了刀,而线程 "B" 获得了叉。线程 A 就会进入阻塞状态来等待获得叉,而线程 B 则阻塞来等待 A 所拥有的刀。这只是人为设计的例子,但尽管在运行时很难探测到,这类情况却时常发生。虽然要探测或推敲各种情况是非常困难的,但只要按照下面几条规则去设计系统,就能够避免死锁问题:
让所有的线程按照同样的顺序获得一组锁。这种方法消除了 X 和 Y 的拥有者分别等待对方的资源的问题。
将多个锁组成一组并放到同一个锁下。前面死锁的例子中,可以创建一个银器对象的锁。于是在获得刀或叉之前都必须获得这个银器的锁。
将那些不会阻塞的可获得资源用变量标志出来。当某个线程获得银器对象的锁时,就可以通过检查变量来判断是否整个银器集合中的对象锁都可获得。如果是,它就可以获得相关的锁,否则,就要释放掉银器这个锁并稍后再尝试。
最重要的是,在编写代码前认真仔细地设计整个系统。多线程是困难的,在开始编程之前详细设计系统能够帮助你避免难以发现死锁的问题。
分享到:
相关推荐
描述Java线程的同步与死锁,加深了解同步与死锁的问题
主要介绍了 Java多线程 线程同步与死锁的相关资料,需要的朋友可以参考下
java-多线程中的同步与死锁笔记
Java多线程--避免同步机制带来的死锁问题及用Lock锁解决线程安全问题
线程同步与妥协处理机制可以较好的解决多线程使用过程中产生的问题。实验中采用了这两种方法后数据混乱、死锁等问题的出现几率大大降低。实验结论表明上面两种方法的使用可以很好的控制死锁、数据混乱的出现,具有...
讲述C#开发过程中,怎么用多线程,需要注意的地方,比如死锁,同步,异步等知识。非本人原著,特别说明。
java多线程知识点,源代码案例,代码案例中包括如何创建线程,主线程,线程优先级,线程组,线程同步,死锁,线程间的通信知识点
python 多线程的同步机制 以python2例程的方式讲解了python 多线程的同步 常用的方法,主要是锁、条件同步、队列 多线程的同步 多线程情况下最常见的问题之一:数据共享; 当多个线程都要去修改某一个共享数据...
编写多线程程序是一件烦琐的技术而且还涉及很多不安全的因素。Java 的出现,使得编写安全高效的多线程技术变得简单,但 ...本文介绍了长途汽车售票系统中所涉及的问题来说明Java 多线程技术同步机制的实现。
《C++面向对象多线程编程》共分13章,全面讲解构建多线程架构与增量多线程编程技术。第1章介绍了用于构建面向对象程序的不同类型C++组件,以及如何使用这些组件来构建多线程架构。第2、3、4章简要介绍进程、线程、多...
您将了解线程安全的实现、死锁的避免策略、线程池的使用方法、线程上下文切换的原因与优化、线程同步与互斥的区别、volatile关键字的作用、synchronized关键字的用法等。同时,我们还探讨了多线程编程中 通过研究和...
所以,互斥锁实质上是操作系统提供的一把“建议锁”(又称“协同锁”),建议程序中有多线程访问共享资源的时候使用该机制。但,并没有强制限定。 因此,即使有了mutex,如果有线程不按规则来访问数据,依然会造成...
Java分布式应用学习笔记05多线程下的并发同步器
介绍 Java 多线程 的PPT 初学者很有帮助
Java线程:线程的同步与锁 Java线程:线程的交互 Java线程:线程的调度-休眠 Java线程:线程的调度-优先级 Java线程:线程的调度-让步 Java线程:线程的调度-合并 Java线程:线程的调度-守护线程 Java线程:...
详细的讲述了多线程的各种用法 Java线程:概念与原理 Java线程:创建与启动 Java线程:线程栈模型与线程的变量 Java线程:线程状态的转换 Java线程:线程的同步与锁 Java线程:线程的交互 Java线程:线程的调度-休眠...
多线程机制 1 1、 Runnable接口与Thread类 1 2、 两个创建线程方法的比较 3 3、 几个常用的改变线程状态的方法 3 4、 线程的同步机制 8 5、 死锁 11 6、 线程间通信,也叫生产者与消费者问题 15 7、 浅析 Java ...
哲学家就餐问题是一个经典的同步问题,用多线程编程实现哲学家就餐问题
Java线程:概念与原理 2 ...五、 关于同步和锁定的一些问题 41 Java线程:并发协作-线程的交互 47 Java线程:并发协作-生产者消费者模型 52 Java线程:并发协作-死锁 55 Java线程:线程之间的数据传递 58