1、死锁情况演示
在多线程中,过多的同步可能会造成死锁。下面以 “一手给钱,一手给货" 为例,创建两个线程类,都拥有相同的对象作为锁对象,显示死锁情况
1.1 线程类1
public class Test implements Runnable{
Object goods ;
Object money ;
public Test(Object goods, Object money) {
super();
this.goods = goods;
this.money = money;
}
@Override
public void run() {
while(true){
test();
}
}
public void test(){
synchronized(goods){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized(money){
}
}
System.out.println("一手给钱");
}
}
1.2 线程类2
public class Test2 implements Runnable{
Object goods ;
Object money ;
public Test2(Object goods, Object money) {
super();
this.goods = goods;
this.money = money;
}
@Override
public void run() {
while(true){
test();
}
}
public void test(){
synchronized(money){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized(goods){
}
}
System.out.println("一手给货");
}
}
1.3 测试
public class SynDemo03 {
public static void main(String[] args) {
//创建共享的两个锁
Object g =new Object();
Object m = new Object();
Test t1 =new Test(g,m);
Test2 t2 = new Test2(g,m);
Thread proxy = new Thread(t1);
Thread proxy2 = new Thread(t2);
proxy.start();
proxy2.start();
}
}
2、生产者消费者模式
当多个线程共享一份资源的时候,会发生死锁的现象,我们一般是通过生产者与消费者模式进行解决。也有称为信号灯法。代码展示如下:
2.1 共享资料电影类:
/**
一个场景,共同的资源
生产者消费者模式 信号灯法
wait() :等待,释放锁 sleep 不释放锁
notify()/notifyAll():唤醒
与 synchronized一起使用
*/
public class Movie {
private String pic ;
//信号灯
//flag -->T 生产生产,消费者等待 ,生产完成后通知消费
//flag -->F 消费者消费 生产者等待, 消费完成后通知生产
private boolean flag =true;
/**
* 播放
*/
public synchronized void play(String pic){
if(!flag){ //生产者等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//开始生产
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("生产了:"+pic);
//生产完毕
this.pic =pic;
//通知消费
this.notify();
//生产者停下
this.flag =false;
}
public synchronized void watch(){
if(flag){ //消费者等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//开始消费
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("消费了"+pic);
//消费完毕
//通知生产
this.notifyAll();
//消费停止
this.flag=true;
}
}
2.2 生产者
/**
* 生产者
*/
public class Player implements Runnable {
private Movie m ;
public Player(Movie m) {
super();
this.m = m;
}
@Override
public void run() {
for(int i=0;i<20;i++){
if(0==i%2){
m.play("左青龙");
}else{
m.play("右白虎");
}
}
}
}
2.3 消费者
public class Watcher implements Runnable {
private Movie m ;
public Watcher(Movie m) {
super();
this.m = m;
}
@Override
public void run() {
for(int i=0;i<20;i++){
m.watch();
}
}
}
2.4 测试
public class App {
public static void main(String[] args) {
//共同的资源
Movie m = new Movie();
//多线程
Player p = new Player(m);
Watcher w = new Watcher(m);
new Thread(p).start();
new Thread(w).start();
}
}
2.5 馒头案例的代码如下:
public class TestProduce {
public static void main(String[] args) {
SyncStack sStack = new SyncStack();
Shengchan sc = new Shengchan(sStack);
Xiaofei xf = new Xiaofei(sStack);
sc.start();
xf.start();
}
}
class Mantou {
int id;
Mantou(int id){
this.id=id;
}
}
class SyncStack{
int index=0;
Mantou[] ms = new Mantou[10];
public synchronized void push(Mantou m){
while(index==ms.length){
try {
this.wait();
//wait后,线程会将持有的锁释放。sleep是即使睡着也持有互斥锁。
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notify(); //唤醒在当前对象等待池中等待的第一个线程。notifyAll叫醒所有在当前对象等待池中等待的所有线程。
//如果不唤醒的话。以后这两个线程都会进入等待线程,没有人唤醒。
ms[index]=m;
index++;
}
public synchronized Mantou pop(){
while(index==0){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notify();
index--;
return ms[index];
}
}
class Shengchan extends Thread{
SyncStack ss = null;
public Shengchan(SyncStack ss) {
this.ss=ss;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("造馒头:"+i);
Mantou m = new Mantou(i);
ss.push(m);
}
}
}
class Xiaofei extends Thread{
SyncStack ss = null;
public Xiaofei(SyncStack ss) {
this.ss=ss;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
Mantou m = ss.pop();
System.out.println("吃馒头:"+i);
}
}
}
3、任务调度Timer
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
/**
了解
Timer()
schedule(TimerTask task, Date time)
schedule(TimerTask task, Date firstTime, long period)
自学 quartz
*/
public class TimeDemo01 {
public static void main(String[] args) {
Timer timer =new Timer();
timer.schedule(new TimerTask(){
@Override
public void run() {
System.out.println("so easy....");
}}, new Date(System.currentTimeMillis()+1000), 200);
}
}