评论区留下邮箱可获得《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多线程设计模式详解》
转载请指明来源