知识点:
1.线程同步产生原因;
2.线程的同步处理操作;
3.线程的死锁情况。
具体内容(了解):
问题的引出:
同步问题是多个线程访问同一个资源的时候需要考虑的问题。
范例:观察非同步情况下的操作。
package 多线程;
class MyThread implements Runnable{
private int ticket = 5; //一共五张票
@Override
public void run() {
for(int x=0;x<20;x++){
if(this.ticket>0){
System.out.println(Thread.currentThread().getName()+"买票,ticket="+this.ticket--);
}
}
}
}
public class T {
public static void main(String[] args) throws Exception {
MyThread mt = new MyThread();
new Thread(mt,"票贩子A").start();
new Thread(mt,"票贩子B").start();
new Thread(mt,"票贩子C").start();
new Thread(mt,"票贩子D").start();
}
}
执行结果:
现在四个线程对象应该一起销售出5张票,此时没有处出现问题是因为是在一个JVM进程下运行,并且没有受到任何的影响,如果想要观察问题可以加入一个延迟来看。
代码:延迟100毫秒
package 多线程;
class MyThread implements Runnable{
private int ticket = 5; //一共五张票
@Override
public void run() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
for(int x=0;x<20;x++){
System.out.println(Thread.currentThread().getName()+"买票,ticket="+this.ticket--);
}
}
}
public class T {
public static void main(String[] args) {
MyThread mt = new MyThread();
new Thread(mt,"票贩子A").start();
new Thread(mt,"票贩子B").start();
new Thread(mt,"票贩子C").start();
new Thread(mt,"票贩子D").start();
}
}
运行结果:
这就是不同步的情况。但是不同步是如何造成的呢?
整个买票的步骤分为两步:
第一步:判断是否还有生于的票数。
第二部:减少剩余的票数。
同步的操作:
通过以上的分析,发现问题是:判断和修改数据是分开完成的,即:某些线程可以同时执行这几个功能。
在java里面如果要实现线程同步可以使用synchronized关键字。可以通过两种方式使用:
方式一:同步代码块
方式二:同步方法
java有四种代码块:普通代码块,构造代码块,静态代码块,同步代码块
范例:观察同步块
package 多线程;
class MyThread implements Runnable{
private int ticket = 5; //一共五张票
@Override
public void run() {
for(int x=0;x<20;x++){
synchronized(this){ //当前操作每一次只允许一个对象进入
if(this.ticket>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"买票,ticket="+this.ticket--);
}
}
}
}
}
public class T {
public static void main(String[] args) {
MyThread mt = new MyThread();
new Thread(mt,"票贩子A").start();
new Thread(mt,"票贩子B").start();
new Thread(mt,"票贩子C").start();
new Thread(mt,"票贩子D").start();
}
}
运行结果:
范例:使用同步方法
package 多线程;
class MyThread implements Runnable{
private int ticket = 5; //一共五张票
@Override
public void run() {
for(int x=0;x<20;x++){
this.sale(); //调用同步方法
}
}
public synchronized void sale(){ //同步方法
if(this.ticket>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"买票,ticket="+this.ticket--);
}
}
}
public class T {
public static void main(String[] args) {
MyThread mt = new MyThread();
new Thread(mt,"票贩子A").start();
new Thread(mt,"票贩子B").start();
new Thread(mt,"票贩子C").start();
new Thread(mt,"票贩子D").start();
}
}
同步相对异步,异步执行速度要高于同步操作,但是同步属于安全的线程操作。
死锁:
同步实际上就是一个线程等待前一个线程操作完毕之后再操作的形式。线程同步过多就容易造成死锁。
死锁是程序开发之中由于某种逻辑上的错误所造成的问题,并且不是简单的就会出现的
面试题:请解释多个线程访问同一资源的需要考虑到那些情况?有可能带来那些问题?
- 多线程访问同一资源时一定要处理好同步,可以使用同步代码块或者同步方法。
_同步代码:synchronized(锁定当前对象){代码}
_同步方法:public synchronized 返回值 方法名(){代码}
- 但是过多的同步,有可能造成死锁。
总结:1.最简单的理解同步和异步的操作那么就可以通过synchronized来实现;
2.死锁是一种不定的状态。