211
技術社區[雲棲]
Java多線程--同步與死鎖:synchronized;等待與喚醒:wait、notify、notifyAll;生命周期
1、問題的引出

class MyThread implements Runnable{
private int ticket = 5 ; // 假設一共有5張票
public void run(){
for(int i=0;i<100;i++){
if(ticket>0){ // 還有票
try{
Thread.sleep(300) ; // 加入延遲
}catch(InterruptedException e){
e.printStackTrace() ;
}
System.out.println("賣票:ticket = " + ticket-- );
}
}
}
};
public class SyncDemo01{
public static void main(String args[]){
MyThread mt = new MyThread() ; // 定義線程對象
Thread t1 = new Thread(mt) ; // 定義Thread對象
Thread t2 = new Thread(mt) ; // 定義Thread對象
Thread t3 = new Thread(mt) ; // 定義Thread對象
t1.start() ;
t2.start() ;
t3.start() ;
}
};


2、同步代碼塊


同步的時候,必須指明同步的對象,一般情況下會將當前對象作為同步對象,使用this表示。
class MyThread implements Runnable{
private int ticket = 5 ; // 假設一共有5張票
public void run(){
for(int i=0;i<100;i++){
synchronized(this){ // 要對當前對象進行同步
if(ticket>0){ // 還有票
try{
Thread.sleep(300) ; // 加入延遲
}catch(InterruptedException e){
e.printStackTrace() ;
}
System.out.println("賣票:ticket = " + ticket-- );
}
}
}
}
};
public class SyncDemo02{
public static void main(String args[]){
MyThread mt = new MyThread() ; // 定義線程對象
Thread t1 = new Thread(mt) ; // 定義Thread對象
Thread t2 = new Thread(mt) ; // 定義Thread對象
Thread t3 = new Thread(mt) ; // 定義Thread對象
t1.start() ;
t2.start() ;
t3.start() ;
}
};
3、同步方法

class MyThread implements Runnable{
private int ticket = 5 ; // 假設一共有5張票
public void run(){
for(int i=0;i<100;i++){
this.sale() ; // 調用同步方法
}
}
public synchronized void sale(){ // 聲明同步方法
if(ticket>0){ // 還有票
try{
Thread.sleep(300) ; // 加入延遲
}catch(InterruptedException e){
e.printStackTrace() ;
}
System.out.println("賣票:ticket = " + ticket-- );
}
}
};
public class SyncDemo03{
public static void main(String args[]){
MyThread mt = new MyThread() ; // 定義線程對象
Thread t1 = new Thread(mt) ; // 定義Thread對象
Thread t2 = new Thread(mt) ; // 定義Thread對象
Thread t3 = new Thread(mt) ; // 定義Thread對象
t1.start() ;
t2.start() ;
t3.start() ;
}
};
4、死鎖
過多的同步可能導致死鎖:死鎖表示在程序時,互相等待。
程序模擬:張三向李四要畫,用書交換;李四向張三要書,用畫交換。
class Zhangsan{ // 定義張三類
public void say(){
System.out.println("張三對李四說:“你給我畫,我就把書給你。”") ;
}
public void get(){
System.out.println("張三得到畫了。") ;
}
};
class Lisi{ // 定義李四類
public void say(){
System.out.println("李四對張三說:“你給我書,我就把畫給你”") ;
}
public void get(){
System.out.println("李四得到書了。") ;
}
};
public class ThreadDeadLock implements Runnable{
private static Zhangsan zs = new Zhangsan() ; // 實例化static型對象
private static Lisi ls = new Lisi() ; // 實例化static型對象
private boolean flag = false ; // 聲明標誌位,判斷那個先說話
public void run(){ // 覆寫run()方法
if(flag){
synchronized(zs){ // 同步張三
zs.say() ;
try{
Thread.sleep(500) ;
}catch(InterruptedException e){
e.printStackTrace() ;
}
synchronized(ls){
zs.get() ;
}
}
}else{
synchronized(ls){
ls.say() ;
try{
Thread.sleep(500) ;
}catch(InterruptedException e){
e.printStackTrace() ;
}
synchronized(zs){
ls.get() ;
}
}
}
}
public static void main(String args[]){
ThreadDeadLock t1 = new ThreadDeadLock() ; // 控製張三
ThreadDeadLock t2 = new ThreadDeadLock() ; // 控製李四
t1.flag = true ;
t2.flag = false ;
Thread thA = new Thread(t1) ;
Thread thB = new Thread(t2) ;
thA.start() ;
thB.start() ;
}
};
5、Object類對線程的支持-----------喚醒和等待:notify、notifyAll、wait


線程操作經典案例程序:生產者和消費之問題,生產者不斷生產,消費者不斷取走生產者生產的產品。
加入等待與喚醒:

class Info{ // 定義信息類
private String name = "李興華"; // 定義name屬性
private String content = "JAVA講師" ; // 定義content屬性
private boolean flag = false ; // 設置標誌位
public synchronized void set(String name,String content){
if(!flag){
try{
super.wait() ;
}catch(InterruptedException e){
e.printStackTrace() ;
}
}
this.setName(name) ; // 設置名稱
try{
Thread.sleep(300) ;
}catch(InterruptedException e){
e.printStackTrace() ;
}
this.setContent(content) ; // 設置內容
flag = false ; // 改變標誌位,表示可以取走
super.notify() ;
}
public synchronized void get(){
if(flag){
try{
super.wait() ;
}catch(InterruptedException e){
e.printStackTrace() ;
}
}
try{
Thread.sleep(300) ;
}catch(InterruptedException e){
e.printStackTrace() ;
}
System.out.println(this.getName() +
" --> " + this.getContent()) ;
flag = true ; // 改變標誌位,表示可以生產
super.notify() ;
}
public void setName(String name){
this.name = name ;
}
public void setContent(String content){
this.content = content ;
}
public String getName(){
return this.name ;
}
public String getContent(){
return this.content ;
}
};
class Producer implements Runnable{ // 通過Runnable實現多線程
private Info info = null ; // 保存Info引用
public Producer(Info info){
this.info = info ;
}
public void run(){
boolean flag = false ; // 定義標記位
for(int i=0;i<50;i++){
if(flag){
this.info.set("李興華","JAVA講師") ; // 設置名稱
flag = false ;
}else{
this.info.set("mldn","www.mldnjava.cn") ; // 設置名稱
flag = true ;
}
}
}
};
class Consumer implements Runnable{
private Info info = null ;
public Consumer(Info info){
this.info = info ;
}
public void run(){
for(int i=0;i<50;i++){
this.info.get() ;
}
}
};
public class ThreadCaseDemo03{
public static void main(String args[]){
Info info = new Info(); // 實例化Info對象
Producer pro = new Producer(info) ; // 生產者
Consumer con = new Consumer(info) ; // 消費者
new Thread(pro).start() ;
new Thread(con).start() ;
}
};
6、線程的生命周期


class MyThread implements Runnable{
private boolean flag = true ; // 定義標誌位
public void run(){
int i = 0 ;
while(this.flag){
System.out.println(Thread.currentThread().getName()
+"運行,i = " + (i++)) ;
}
}
public void stop(){
this.flag = false ; // 修改標誌位
}
};
public class StopDemo{
public static void main(String args[]){
MyThread my = new MyThread() ;
Thread t = new Thread(my,"線程") ; // 建立線程對象
t.start() ; // 啟動線程
try{
Thread.sleep(30) ;
}catch(Exception e){
}
my.stop() ; // 修改標誌位,停止運行
}
};
最後更新:2017-04-03 14:53:40