package com.csdn; class Tickets{ public int tickets; public Tickets(){ tickets = 10; } } public class SaleTicket { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Tickets t = new Tickets(); Ticket st1 = new Ticket(t,"小王"); Ticket st2 = new Ticket(t,"小张"); } } class Ticket extends Thread { Tickets t; String name; public Ticket(Tickets t,String name){ this.t = t; this.name = name; start(); } @Override public void run() { // TODO Auto-generated method stub for(int i=0; i<5; i++){ System.out.println(name+"抢到了第"+t.tickets+"票号"); t.tickets--; try { Thread.sleep(20); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
package com.csdn; public class SaleTickets { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub SaleTicke st = new SaleTicke(); Thread t1 = new Thread(st); Thread t2 = new Thread(st); t1.start(); t2.start(); } } class SaleTicke implements Runnable{ private int tickets = 20; @Override public void run() { // TODO Auto-generated method stub while(true){ if(tickets>0){ try { Thread.sleep(20); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"......"+tickets--); } } } }
为什么需要“线程同步” ??
线程间共享代码和数据可以节省系统开销,提高程序运行效率,但同时也导致了数据的“访问冲突”问题
如何实现线程间的有机交互、并确保共享资源在某些关键时段只能被一个线程访问,即所谓的“线程同步”(Synchronization)就变得至关重要。
临界资源: 多个线程间共享的数据称为临界资源(Critical Resource),
由于是线程调度器负责线程的调度,程序员无法精确控制多线程的交替顺序。因此,多线程对临界资源的访问有时会导致数据的不一致行。
互斥锁
每个对象都对应于一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。
Java对象默认是可以被多个线程共用的,只是在需要时才启动“互斥锁”机制,成为专用对象。
关键字synchronized用来与对象的互斥锁联系
当某个对象用synchronized修饰时,表明该对象已启动“互斥锁”机制,在任一时刻只能由一个线程访问,即使该线程出现堵塞,该对象的被锁定状态也不会解除,其他线程任不能访问该对象。
synchronized关键字的使用方式有两种:
1.同步代码块
synchronized(对象){
需要同步的代码
}
2.同步函数: 使用的锁是this
public synchronized void show(){
}
package com.csdn; class Tickets1{ public int tickets; public Tickets1(){ tickets = 10; } } public class TestMulThread2{ /** * @param args */ public static void main(String[] args) { Tickets1 t = new Tickets1(); Ticket1 st1 = new Ticket1(t,"小王"); Ticket1 st2 = new Ticket1(t,"小张"); } } class Ticket1 extends Thread { static String st1 ="aaa"; Tickets1 t; String name; public Ticket1(Tickets1 t,String name){ this.t = t; this.name = name; start(); } public synchronized void show(){//同步代码块 System.out.println(name+"抢到了第"+t.tickets+"票号"); t.tickets--; } @Override public void run() { for(int i=0; i<5; i++){ synchronized(st1){ System.out.println(name+"抢到了第"+t.tickets+"票号"); t.tickets--; } //show(); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
package com.csdn; public class SaleTicketsSy { public static void main(String[] args) { // TODO Auto-generated method stub SaleTicketsy st = new SaleTicketsy(); Thread t1 = new Thread(st); Thread t2 = new Thread(st); t1.start(); t2.start(); } } class SaleTicketsy implements Runnable{ private int tickets = 100; @Override public void run() { // TODO Auto-generated method stub Object obj = new Object(); while(true){ synchronized(obj){//同步代码块 if(tickets>0){ try { Thread.sleep(20); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"......"+tickets--); } } } } }
package com.csdn; public class TestMulThread { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Tickets2 t = new Tickets2(); TicketsThread d1 = new TicketsThread(t,"Jam"); TicketsThread d2 = new TicketsThread(t,"Jack"); } } class Tickets2{ public int tickets; public Tickets2(){ tickets = 10; } public synchronized void action(String name){//锁方法 System.out.println(name+"抢到了第"+tickets+"票号"); tickets--; } } class TicketsThread extends Thread{ Tickets2 t; String name; public TicketsThread(Tickets2 t, String name){ this.t = t; this.name = name; start(); } public void run(){ for(int i=0;i<5;i++){ t.action(name); try { Thread.sleep(20); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
package com.csdn; public class SaleTicketsSy2 { public static void main(String[] args) { // TODO Auto-generated method stub SaleTicketsy2 st = new SaleTicketsy2(); Thread t1 = new Thread(st); Thread t2 = new Thread(st); t1.start(); t2.start(); } } class SaleTicketsy2 implements Runnable{ private int tickets = 100; @Override public void run() { // TODO Auto-generated method stub while(true){ show(); } } public synchronized void show(){//锁方法 if(tickets>0){ try { Thread.sleep(20); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"......"+tickets--); } } }
同步好处:决了线程安全问题
同步弊端:降低了运行效率(判断锁是较为消耗资源的)
死锁:同步嵌套,容易出现死锁
死锁 两个线程A、B用到同一个对象s(s为共享资源),且线程A在执行中要用到B运行后所创造的条件。在这种前提下A先开始运行,进入同步块后,对象s被锁定,接着线程A因等待B运行结束而进入阻塞状态,于是B开始运行,但因无法访问对象s,线程B也进入阻塞状态,等待s被线程A解锁。最终的结果:两个线程互相等待,都无法运行。
package com.csdn; public class DeadLock { /** * @param args */ public static void main(String[] args) { Demo6 d1=new Demo6(true); Demo6 d2=new Demo6(false); Thread t1=new Thread(d1); Thread t2=new Thread(d2); t1.start(); t2.start(); } } class MyLock{ static MyLock lock1=new MyLock(); static MyLock lock2=new MyLock(); } class Demo6 implements Runnable{ //String str1=new String("aaa"); //String str2=new String("bbb"); private boolean flag; public Demo6(boolean flag){ this.flag=flag; } @Override public void run() { if(flag){ synchronized(MyLock.lock1){ System.out.println(Thread.currentThread().getName()+"...if...str1"); synchronized(MyLock.lock2){ System.out.println(Thread.currentThread().getName()+"...if...str2"); } } }else{ synchronized(MyLock.lock2){ System.out.println(Thread.currentThread().getName()+"...else...str2"); synchronized(MyLock.lock1){ System.out.println(Thread.currentThread().getName()+"...else...str1"); } } } } }
分析:这是线程死锁的典型表现,两个以上线程并发运行,他们均因其他线程锁定了自己运行所需资源而陷入阻塞状态,同时自己也锁定了其他线程所需资源。
单例类
懒汉式
class Single{
private static Single s=null;
private Single(){}
public static Single getInstance(){
if(s==null)
synchronized(Singel。class){
if(s==null)
s=new Single();
}
return s;
}
class Single{
private static Single s=null;
private Single(){}
public static synchronized Single getInstance(){
if(s==null)
s=new Single();
return s;}
Single.getInstance();
饿汉式
class Single{
private static Single s=new Single();
private Single(){}
public static Single getInstance(){
return s;
}
}