JavaFX 多线程学习(2)

  一、 synchronized

多个线程如果共享资源的情况下, 很容易的就会导致资源出现混乱,就以买票的程序为例子,先创建一个SellTicket对象,设置总票数为100张的情况下,设置四个窗口售卖这一百张票。

// SellTicket.java
import com.sun.org.apache.xml.internal.resolver.Catalog;

public class SellTicket implements Runnable {

	private int tickteCount = 100;

	@Override
	public void run() {
		try {
			while (tickteCount > 0) {
				sellTicket();
				// 让线程睡一会,以免太快把票卖完
				Thread.sleep(100);
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	private void sellTicket() {
		if (tickteCount > 0) {
			tickteCount--;
			System.out.println(Thread.currentThread().getName() + "买票, " + "还剩" + tickteCount + "张票。");
		} else {
			System.out.println("票卖完了");
		}
	}
}
//Demo1.java
import jdk.nashorn.internal.runtime.regexp.joni.exception.InternalException;

public class Demo1 {
    public static void main(String[] args) throws InterruptedException {
    	
    	
    	// 让多个线程操作一个对象的资源,而不是new多个SellTicket() 对象.
    	SellTicket ticket = new SellTicket();
   
    	Thread t1 = new Thread(ticket,"窗口1");
    	Thread t2 = new Thread(ticket,"窗口2");
    	Thread t3 = new Thread(ticket,"窗口3");
    	Thread t4 = new Thread(ticket,"窗口4");
    	
    	t1.start();
    	t2.start();
    	t3.start();
    	t4.start(); 
    	
    }
    
}
`

  程序运行之后,出现如下结果:

窗口1买票, 还剩98张票。
窗口2买票, 还剩98张票。
窗口3买票, 还剩97张票。
窗口4买票, 还剩96张票。
窗口1买票, 还剩94张票。
窗口3买票, 还剩93张票。
窗口2买票, 还剩94张票。
窗口4买票, 还剩92张票。
窗口1买票, 还剩90张票。
窗口4买票, 还剩89张票。
窗口2买票, 还剩90张票。
窗口3买票, 还剩90张票。
窗口1买票, 还剩87张票。
窗口3买票, 还剩86张票。
窗口4买票, 还剩87张票。
窗口2买票, 还剩87张票。
窗口1买票, 还剩85张票。
窗口2买票, 还剩82张票。
窗口4买票, 还剩83张票。
窗口3买票, 还剩83张票。
窗口4买票, 还剩81张票。
窗口3买票, 还剩80张票。
窗口2买票, 还剩81张票。
窗口1买票, 还剩81张票。
窗口2买票, 还剩78张票。
窗口1买票, 还剩77张票。
窗口3买票, 还剩78张票。
窗口4买票, 还剩78张票。
窗口2买票, 还剩75张票。
窗口4买票, 还剩73张票。
窗口3买票, 还剩74张票。
窗口1买票, 还剩75张票。
窗口2买票, 还剩72张票。
窗口1买票, 还剩69张票。
窗口3买票, 还剩70张票。
窗口4买票, 还剩71张票。
窗口2买票, 还剩67张票。
窗口4买票, 还剩65张票。
窗口3买票, 还剩66张票。
窗口1买票, 还剩67张票。
窗口4买票, 还剩64张票。
窗口2买票, 还剩64张票。
窗口3买票, 还剩62张票。
窗口1买票, 还剩62张票。
窗口4买票, 还剩60张票。
窗口1买票, 还剩59张票。
窗口2买票, 还剩60张票。
窗口3买票, 还剩60张票。
窗口4买票, 还剩58张票。
窗口3买票, 还剩55张票。
窗口1买票, 还剩56张票。
窗口2买票, 还剩56张票。
窗口4买票, 还剩54张票。
窗口3买票, 还剩53张票。
窗口2买票, 还剩51张票。
窗口1买票, 还剩52张票。
窗口4买票, 还剩50张票。
窗口2买票, 还剩49张票。
窗口1买票, 还剩48张票。
窗口3买票, 还剩48张票。
窗口4买票, 还剩47张票。
窗口2买票, 还剩46张票。
窗口1买票, 还剩45张票。
窗口3买票, 还剩44张票。
窗口4买票, 还剩43张票。
窗口2买票, 还剩42张票。
窗口3买票, 还剩40张票。
窗口1买票, 还剩41张票。
窗口4买票, 还剩39张票。
窗口3买票, 还剩37张票。
窗口1买票, 还剩36张票。
窗口2买票, 还剩37张票。
窗口4买票, 还剩35张票。
窗口2买票, 还剩33张票。
窗口1买票, 还剩32张票。
窗口3买票, 还剩32张票。
窗口4买票, 还剩31张票。
窗口1买票, 还剩30张票。
窗口2买票, 还剩29张票。
窗口3买票, 还剩30张票。
窗口4买票, 还剩28张票。
窗口1买票, 还剩27张票。
窗口3买票, 还剩25张票。
窗口2买票, 还剩26张票。
窗口4买票, 还剩24张票。
窗口1买票, 还剩23张票。
窗口2买票, 还剩21张票。
窗口3买票, 还剩22张票。
窗口4买票, 还剩20张票。
窗口1买票, 还剩19张票。
窗口3买票, 还剩18张票。
窗口2买票, 还剩19张票。
窗口4买票, 还剩17张票。
窗口1买票, 还剩16张票。
窗口3买票, 还剩16张票。
窗口2买票, 还剩15张票。
窗口4买票, 还剩14张票。
窗口1买票, 还剩13张票。
窗口2买票, 还剩12张票。
窗口3买票, 还剩12张票。
窗口4买票, 还剩11张票。
窗口1买票, 还剩10张票。
窗口3买票, 还剩8张票。
窗口2买票, 还剩9张票。
窗口4买票, 还剩7张票。
窗口3买票, 还剩5张票。
窗口2买票, 还剩4张票。
窗口1买票, 还剩5张票。
窗口4买票, 还剩3张票。
窗口2买票, 还剩2张票。
窗口1买票, 还剩1张票。
窗口3买票, 还剩2张票。
窗口4买票, 还剩0张票。

  很明显, 窗口重复售卖了同一张票,是因为在下面这段代码中:

if (tickteCount > 0) {
			// 有可能CPU在这个时候切换了,已经进入到另外一个线程里面。
			tickteCount--;
			System.out.println(Thread.currentThread().getName() + "买票, " + "还剩" + tickteCount + "张票。");
		} else {
			System.out.println("票卖完了");
		}

线程1 可能已经进入到if里面了,但是CPU资源分配到其他线程,导致该线程停在这里,资源就会出现混乱。

解决方法:在synchronized(Object)里面写代码。

synchronized(Object),运行到该代码块的线程回去尝试获取Object的锁, 如果获取到了,就会执行synchronized{}里面的代码,否则就会不执行。

//SellTicket.java
import com.sun.org.apache.xml.internal.resolver.Catalog;

public class SellTicket implements Runnable {

	private int tickteCount = 100;
	
	private Object obj = new Object();

	@Override
	public void run() {
		try {
			while (tickteCount > 0) {
				sellTicket();
				// 让线程睡一会,以免太快把票卖完
				Thread.sleep(100);
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	private void sellTicket() {
		synchronized (obj) {  // 同步代码块 锁 任何一个对象
			if (tickteCount > 0) {
				tickteCount--;
				System.out.println(Thread.currentThread().getName() + "买票, " + "还剩" + tickteCount + "张票。");
			} else {
				System.out.println("票卖完了");
			}
		}
		
	}
}

运行结果:
窗口1买票, 还剩99张票。
窗口4买票, 还剩98张票。
窗口3买票, 还剩97张票。
窗口2买票, 还剩96张票。
窗口4买票, 还剩95张票。
窗口3买票, 还剩94张票。
窗口2买票, 还剩93张票。
窗口1买票, 还剩92张票。
窗口3买票, 还剩91张票。
窗口2买票, 还剩90张票。
窗口1买票, 还剩89张票。
窗口4买票, 还剩88张票。
窗口3买票, 还剩87张票。
窗口1买票, 还剩86张票。
窗口2买票, 还剩85张票。
窗口4买票, 还剩84张票。
窗口1买票, 还剩83张票。
窗口2买票, 还剩82张票。
窗口3买票, 还剩81张票。
窗口4买票, 还剩80张票。
窗口1买票, 还剩79张票。
窗口3买票, 还剩78张票。
窗口2买票, 还剩77张票。
窗口4买票, 还剩76张票。
窗口3买票, 还剩75张票。
窗口2买票, 还剩74张票。
窗口1买票, 还剩73张票。
窗口4买票, 还剩72张票。
窗口3买票, 还剩71张票。
窗口1买票, 还剩70张票。
窗口2买票, 还剩69张票。
窗口4买票, 还剩68张票。
窗口3买票, 还剩67张票。
窗口2买票, 还剩66张票。
窗口1买票, 还剩65张票。
窗口4买票, 还剩64张票。
窗口3买票, 还剩63张票。
窗口2买票, 还剩62张票。
窗口1买票, 还剩61张票。
窗口4买票, 还剩60张票。
窗口3买票, 还剩59张票。
窗口1买票, 还剩58张票。
窗口2买票, 还剩57张票。
窗口4买票, 还剩56张票。
窗口3买票, 还剩55张票。
窗口2买票, 还剩54张票。
窗口1买票, 还剩53张票。
窗口4买票, 还剩52张票。
窗口3买票, 还剩51张票。
窗口1买票, 还剩50张票。
窗口2买票, 还剩49张票。
窗口4买票, 还剩48张票。
窗口3买票, 还剩47张票。
窗口2买票, 还剩46张票。
窗口1买票, 还剩45张票。
窗口4买票, 还剩44张票。
窗口3买票, 还剩43张票。
窗口1买票, 还剩42张票。
窗口2买票, 还剩41张票。
窗口4买票, 还剩40张票。
窗口3买票, 还剩39张票。
窗口2买票, 还剩38张票。
窗口1买票, 还剩37张票。
窗口4买票, 还剩36张票。
窗口3买票, 还剩35张票。
窗口1买票, 还剩34张票。
窗口2买票, 还剩33张票。
窗口4买票, 还剩32张票。
窗口3买票, 还剩31张票。
窗口1买票, 还剩30张票。
窗口2买票, 还剩29张票。
窗口4买票, 还剩28张票。
窗口3买票, 还剩27张票。
窗口1买票, 还剩26张票。
窗口2买票, 还剩25张票。
窗口4买票, 还剩24张票。
窗口3买票, 还剩23张票。
窗口1买票, 还剩22张票。
窗口2买票, 还剩21张票。
窗口4买票, 还剩20张票。
窗口3买票, 还剩19张票。
窗口2买票, 还剩18张票。
窗口1买票, 还剩17张票。
窗口4买票, 还剩16张票。
窗口3买票, 还剩15张票。
窗口2买票, 还剩14张票。
窗口1买票, 还剩13张票。
窗口4买票, 还剩12张票。
窗口3买票, 还剩11张票。
窗口2买票, 还剩10张票。
窗口1买票, 还剩9张票。
窗口4买票, 还剩8张票。
窗口3买票, 还剩7张票。
窗口2买票, 还剩6张票。
窗口1买票, 还剩5张票。
窗口4买票, 还剩4张票。
窗口3买票, 还剩3张票。
窗口2买票, 还剩2张票。
窗口1买票, 还剩1张票。
窗口4买票, 还剩0张票。

另外,也可以在方法上面加上synchronized, 使得该方法变成一个同步方法,synchronized 获取的锁就是从本身这个对象的锁获取的。

private synchronized void sellTicket() {
//		synchronized (obj) {  // 同步代码块 锁 任何一个对象
			if (tickteCount > 0) {
				tickteCount--;
				System.out.println(Thread.currentThread().getName() + "买票, " + "还剩" + tickteCount + "张票。");
			} else {
				System.out.println("票卖完了");
			}
//		}
		
	}

二、线程之间的唤醒(三个方法必须写在synchronized代码块里面)

 

// Waiter.java

public class Waiter implements Runnable {
	
	
	private Message message;// 使用message来加锁
	
	public Waiter(Message message) {
	    this.message = message;
	}

	@Override
	public void run() {
		
		String name = Thread.currentThread().getName();
		synchronized (message) {
		    try {
		    	System.out.println(name + " 等待时间" + System.currentTimeMillis());
		    	message.wait();
		    	System.out.println(message.getMessage() + System.currentTimeMillis());
		    }catch (InterruptedException e) {
			    e.printStackTrace();
			}
		}
	}
}
//Notifier.java

public class Notifier implements Runnable{
	
	Message message;
	
    public Notifier(Message message) {
    	this.message = message;
    }

	@Override
	public void run() {
		String name = Thread.currentThread().getName();
		
		synchronized(message) {
			message.setMessage("唤醒线程工作");
			message.notify();
		}
	}
    
}
//Demo1.java
import jdk.nashorn.internal.runtime.regexp.joni.exception.InternalException;

public class Demo1 {
    public static void main(String[] args) throws InterruptedException {
    	
    	Message message = new Message("锁");
    	
    	Waiter waiter1 = new Waiter(message);
    	Waiter waiter2 = new Waiter(message);
    	
    	Notifier notifier = new Notifier(message);
    	
    	new Thread(waiter1, "waiter1").start();;
    	new Thread(waiter2, "waiter2").start();;
    	new Thread(notifier,"notifier").start();
    	
    	new Thread();
    }
    
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值