Java多线程详解(二)

     

评论区留下邮箱可获得《Java多线程设计模式详解》

转载请指明来源

 1)后台线程

  后台线程是为其他线程服务的一种线程,像JVM的垃圾回收线程就是一种后台线程。后台线程总是等到非后台线程死亡之后,后台线程没有了服务对象,不久就会自动死亡,不再复活。利用setDaemon方法可以把一个线程设置为后台线程,但必须在线程启动之前调用。

   例如 :

/*
 * @author  wxismeit@163.com
 */
public class DaemonThread extends Thread {
	public void run() {
		for(int i=0; i<100; i++) {
			System.out.println(getName() + " " + i);
		}
	}

	public static void main(String[] args) throws InterruptedException {
		DaemonThread dt = new DaemonThread();
		dt.setDaemon(true);//必须在启动线程之前调用
		dt.start();
		System.out.println(dt.isDaemon());//true
		for(int i=0; i<10; i++) {
			System.out.println(Thread.currentThread().getName() + " " + i);
			Thread.sleep(1000);//让当前线程睡眠1s,进入阻塞状态。其他线程可以执行
		}
		//在主线程main结束不久,后台线程st也会死亡

	}

}


 

2)线程让步 :yield

让当前线程暂停,但不阻塞该线程。让该线程转入就绪状态。系统根据优先级重新调度线程。可以使用setPriority方法设置线程的优先级。

例如:

public class YieldThread extends Thread {
	public YieldThread(String name) {
		super(name);
	}
	public void run() {
		for(int i=0; i<50; i++) {
			System.out.println(getName() + " " + i);
			if(i == 20) {
				Thread.yield();//让当前线程让步
			}
		}
	}

	public static void main(String[] args) {
		YieldThread yt1 = new YieldThread("high");
		YieldThread yt2 = new YieldThread("low");
		yt1.setPriority(MAX_PRIORITY);//优先级设为高级
		yt1.start();
		yt2.setPriority(MIN_PRIORITY);//优先级设为低级
		yt2.start();
	}

}

3)sleep  和 yield的区别

sleep暂停时,进入阻塞状态,其他线程会执行,不考虑优先级。而yield暂停时进入就绪状态。只会给优先级相同或更高的线程执行机会。

4)线程同步

在银行取钱时 如果两个线程同时操作一个账户,就会出现不应该的错误,这就是线程不安全的。那么如何能让线程成为安全的呢。

public class Account {
	private String accountNo;
	private double balance;
	public Account() {};
	public Account(String a,double b) {
		accountNo = a;
		balance = b;
	}
	public void setaccountNo(String accountNo) {
	      this.accountNo = accountNo;
	}
	public void setbalance(double balance) {
		this.balance = balance;
	}
	public String getaccountNo() {
		return this.accountNo;
	}
	public double getbalance() {
		return this.balance;
	}
	//重写hashcode方法
	public int hashCode() {
		return accountNo.hashCode();
	}
	//重写equals方法
	public boolean equals(Object obj) {
		if(this == obj) return true;
		if(obj != null && obj.getClass() == Account.class) {
			Account a = (Account)obj;
			return a.getaccountNo().equals(accountNo);
		}
		return false;
	}
	

}


 

public class Withdraw extends Thread{
	private Account account;
	private double drawNo;
	public Withdraw(String name, Account a, double d) {
		super(name);
		account = a;
		drawNo = d;
	}
	
	public void run() {
		//synchronized(account) {//锁定对象,其他线程无法获得,无法修改账户。
		if(account.getbalance() >= drawNo) {
			System.out.println("所取钱数为 :" + drawNo);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			account.setbalance(account.getbalance() - drawNo);
			System.out.println("余额为: " + account.getbalance());
		}else {
			System.out.println("取钱失败!");
		//}	
		}
	}
	


}


 

public class DrawMoney {

	public static void main(String[] args) {
		Account ac = new Account("wangxu", 1000);
		new Withdraw("甲", ac, 800).start();
		new Withdraw("乙", ac, 800).start();
	}
}


如上代码所示,在修改能够引发线程不安全问题的时候,就要锁定。这时可以用代码同步块和同步方法来锁定,所用关键字为synchronized。具体不再赘述。

4)同步锁

为了更灵活的解决线程安全问题,Java引入了同步锁。有读写锁,可重入锁等。

举个简单的例子:

import java.util.concurrent.locks.ReentrantLock;


public class lock {
	private final ReentrantLock lock = new ReentrantLock();
	//需要线程安全的方法
	public void f() {
		lock.lock();//加锁
		try{
			//...
		}finally {
			lock.unlock();//释放锁
		}
	}

}


关于死锁和线程通信下次更新。

评论区留下邮箱可获得《Java多线程设计模式详解》

转载请指明来源

原文地址:https://www.cnblogs.com/wxisme/p/4363755.html