/**
* 需求:簡單的賣票程序。
多個窗口同時買票。
思路:多個窗口就是多個線程。
票就是共享的數據,每個線程都有唯一的它
*/
注意:線程終止的時刻是run方法裏的while循環終止的時候。
public class TicketDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
//創建共享數據票
Ticket t=new Ticket(100);
new SellTicket(t).start();
new SellTicket(t).start();
}
}
//票
class Ticket
{
//初始化票爲100張
private int i=100;
public Ticket (int i)
{
this.i=i;
}
public int getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
}
//買票的線程
class SellTicket extends Thread
{
private Ticket t;
public SellTicket (Ticket t)
{
this.t=t;
}
@Override
public void run() {
// TODO Auto-generated method stub
while(t.getI()>0)
{
// try {
// Thread.sleep(1000);
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// 使用同步代碼塊,防止兩個窗口打印無法同步
synchronized(this.t)
{
System.out.println(Thread.currentThread().getName()+"剩餘票數爲"+t.getI());
t.setI(t.getI()-1);
}
}
}
}
/*** 靜態的同步函數使用的鎖是 該函數所屬字節碼文件對象
可以用 getClass方法獲取,也可以用當前 類名.class 表示即該類。
*/
public class StaticSynFunctionDemo {
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
Tick t=new Tick();
Thread t1=new Thread (t);
Thread t2=new Thread(t);
//t1將會只執行run的同步代碼塊
t1.start();
Thread.sleep(1000);
t.flag=false;
//t2將只會執行同步方法showTick。
t2.start();
}
}
//票:同步代碼塊與靜態方法同步
class Tick implements Runnable
{
private static int i=100;
//一個標誌位,決定由同步方法執行,還是同步代碼塊執行
boolean flag=true;
@Override
public void run() {
// TODO Auto-generated method stub
if(flag)
{
//拿到flag爲true的線程將在這裏不停的循環
while(true)
{
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (Tick.class)
{
System.out.println(Thread.currentThread().getName()+"--run代碼塊--"+i--);
}
}
}else
{
//拿到flag爲false的線程將不停的在這裏離循環
while(true)
{
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
showTick();
}
}
}
public static synchronized void showTick ()
{
System.out.println(Thread.currentThread().getName()+"--showTick方法--"+i--);
}
}
/**
* 死鎖:常見情景之一:同步的嵌套。即線程x要先拿a,再拿b兩個鎖纔可以執行下去,而線程y剛好相反。
剛好x拿了a鎖時,y也拿了b鎖,接下來雙發互強對方線程手上的鎖。
* 總結死鎖原因:一:執行同步時要拿兩個不同的對象鎖
* 二:第二個對象鎖被別的線程拿走了,且不還,不釋放
* 導致拿了第一個對象鎖的線程無法執行下去。
*/
public class DeadLockDemo {
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
Piao p=new Piao();
Thread t1=new Thread(p);
Thread t2=new Thread(p);
t1.start();
Thread.sleep(1);
p.flag=false;
t2.start();
}
}
//票
class Piao implements Runnable
{
private int i=100;
//用來做同步的鎖
Object o=new Object();
//標誌位,不同線程執行不同標誌位下的代碼
boolean flag=true;
@Override
public void run() {
// TODO Auto-generated method stub
if(flag)
{
while(true)
{
//flag爲true的線程在此執行,
//執行下面的第一件事情是拿到對象o的鎖
synchronized (o)
{
//執行下面的第一件事情是拿到該對象鎖piao
show();
}
}
}else
{
while(true)
{
//flag爲false的線程執行下面show()方法
//執行show方法的第一個事情是拿到該對象鎖piao.
this.show();
}
}
}
public synchronized void show()
{
synchronized (o)
{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-show方法-"+i--);
}
}
}