1、线程的同步产生的原因
没有同步的情况
class MyThread1 implements Runnable
{
private int ticket=5;
@Override
public void run() {
for(int x =0;x<20;x++)
{
if(ticket>0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"卖票:"+this.ticket--);
}
}
}
}
public class Test {
public static void main(String[] args) {
MyThread1 mt = new MyThread1();
new Thread(mt,"票贩子A").start();
new Thread(mt,"票贩子B").start();
new Thread(mt,"票贩子C").start();
new Thread(mt,"票贩子D").start();
}
}
票贩子C卖票:5
票贩子D卖票:5
票贩子B卖票:4
票贩子A卖票:3
票贩子D卖票:2
票贩子C卖票:1
票贩子A卖票:-1
票贩子B卖票:0
票贩子D卖票:-2
可以看到又相同的票被卖了,还出现了负数票的情况。
2、线程的同步处理操作
实现同步的关键字synchronized,可以通过两种方式使用
- 一种是同步代码块
- 另外一种是同步方法
在Java里面有四种代码块:普通代码块、构造块、静态块、同步块
使用同步代码块实现同步
class MyThread1 implements Runnable
{
private int ticket=10;
@Override
public void run() {
for(int x =0;x<20;x++)
{
synchronized(this){
if(ticket>0) {
System.out.println(Thread.currentThread().getName()+"卖票:"+this.ticket--);
}
}
}
}
}
public class SynchronizedThread {
public static void main(String[] args) {
MyThread1 mt = new MyThread1();
new Thread(mt,"票贩子A").start();
new Thread(mt,"票贩子B").start();
new Thread(mt,"票贩子C").start();
new Thread(mt,"票贩子D").start();
}
}
票贩子A卖票:10
票贩子D卖票:9
票贩子C卖票:8
票贩子B卖票:7
票贩子C卖票:6
票贩子C卖票:5
票贩子C卖票:4
票贩子D卖票:3
票贩子A卖票:2
票贩子D卖票:1
调用同步方法实现同步
class MyThread1 implements Runnable
{
private int ticket=10;
@Override
public void run() {
for(int x =0;x<20;x++)
{
this.sale();
}
}
public synchronized void sale()
{
if(ticket>0) {
System.out.println(Thread.currentThread().getName()+"卖票:"+this.ticket--);
}
}
}
public class SynchronizedThread {
public static void main(String[] args) {
MyThread1 mt = new MyThread1();
new Thread(mt,"票贩子A").start();
new Thread(mt,"票贩子B").start();
new Thread(mt,"票贩子C").start();
new Thread(mt,"票贩子D").start();
}
}
3、线程的死锁情况
Java 实例 - 死锁及解决方法
死锁是这样一种情形:多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不可能正常终止。
java 死锁产生的四个必要条件:
1、互斥使用,即当资源被一个线程使用(占有)时,别的线程不能使用
2、不可抢占,资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放。
3、请求和保持,即当资源请求者在请求其他的资源的同时保持对原有资源的占有。
4、循环等待,即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了一个等待环路。
解决方法:
- 用信号量去控制死锁。
- 调整申请锁的范围
- 调整申请锁的顺序
避免死锁:银行家算法。
请解释多个线程访问统一资源时需要考虑哪些情况?有可能带来哪些后果?
多个线程访问同一资源时要考虑到线程间的同步问题,可以使用同步代码或同步方法解决;
同步代码块:synchronized(锁定对象){代码}
同步方法: public synchronized 返回值 方法名称(){代码}
但是过多的使用同步,有可能造成死锁。