网上对线程的总结:http://lavasoft.blog.51cto.com/62575/27069
定义表示线程的类有两种方法:
一种是将其定义为Thread类的子类,并提供run()方法的定义来替代继承的run()方法。
另一种方法将其定义为接口Runnable的形式。这个接口声明run()方法,然后在需要的时候在类中创建一个Thread对象。
-------------------------------------------------------------
16.1理解线程
创建线程 | 停止线程 | 连接线程 | 线程调度 | 实现Runnable接口
守护线程和用户进程
setDaemon(true)将线程设为守护线程。守护线程只是一个后台运行的线程,它从属于创建它的线程,所以当创建守护进程的线程结束时,守护线程也随之消亡。
由守护线程创建的线程默认为守护线程。
import java.io.IOException; public class TryThread extends Thread{ public TryThread(String firstName, String secondName, long delay){ this.firstName = firstName; this.secondName = secondName; aWhile = delay; setDaemon(true);//守护进程 } public static void main(String[] args){ Thread first = new TryThread("Hopalong ", "Cassidy ", 200L); Thread second = new TryThread("Marilyn ", "Monroe ", 300L); Thread third = new TryThread("Slim ", "Pickens ", 500L); System.out.println("Press Enter when you have had enough...n"); first.start(); second.start(); third.start(); try{ System.in.read(); System.out.println("Enter pressed...n"); } catch(IOException e){ System.out.println(e); } System.out.println("Ending main()"); return; } public void run(){ try{ while(true){ System.out.print(firstName); sleep(aWhile); System.out.print(secondName + "n"); } } catch(InterruptedException e){ System.out.println(firstName + secondName + e); } } private String firstName; private String secondName; private long aWhile; }
将线程设置到执行状态 / 将线程设置到中止状态
start() / interrupt()
测试线程是否仍在运行,可以调用isAlive方法。
测试线程是否已经中断,可以调用isInterrupted方法。
连接线程:如果一个线程中需要等待另一个线程消亡,可以调用join方法来处理希望消亡的线程。无参数调用join()将暂停当前线程,直到指定线程消亡。也可以传递一个long类型的值,指定等待的毫秒数。 代码实例http://www.cnblogs.com/jimwind/p/3259139.html
线程调度:每个线程,在其他线程调用sleep时,都有机会执行。如果操作系统采用抢占式的任务调度,那么不在run()方法中调用sleep,程序也能运行(如果去掉sleep,也要去掉try块和catch块)。但是,如果操作系统不是以这种方式调度的,在run方法中不调用sleep,第一个线程就会独占处理器并无限地继续下去。
即:通过调用sleep来放弃控制权,让其它线程有机会运行。
还有一个方法,yield(),它与sleep的区别是,当调用sleep时,即使没有其他线程等待,该线程也会至少停止由实参所指定的一段时间,然而,调用yeid时,如果没有其他线程待,当前线程就马上重新开始执行。PS:那貌似yield方法好多了啊。百度了一下,跟优先级有关。
以上,应该关注的四个方法,setDaemon, join, sleep, yield
实现Runnable接口
import java.io.IOException; public class JumbleNames implements Runnable{ public JumbleNames(String firstName, String secondName, long delay){ this.firstName = firstName; this.secondName = secondName; aWhile = delay; } public void run(){ try{ while(true){ System.out.print(firstName); Thread.sleep(aWhile); System.out.print(secondName + "\n"); } } catch (InterruptedException e){ System.out.println(firstName + secondName + e); } } public static void main(String[] args){ Thread first = new Thread(new JumbleNames("Hopalong ", "Cassidy ", 200L)); Thread second = new Thread(new JumbleNames("Marilyn ", "Monroe ", 300L)); Thread third = new Thread(new JumbleNames("Slim ", "Pickens ", 500L)); first.setDaemon(true); second.setDaemon(true); third.setDaemon(true); System.out.println("Press Enter when you have had enough...\n"); first.start(); second.start(); third.start(); try{ System.in.read(); System.out.println("Enter pressed...\n"); } catch(IOException e){ System.out.println(e); } System.out.println("Ending main()"); return; } private String firstName; private String secondName; private long aWhile; }
线程的名称: Thead first = new Thread(new JumbleNames("Hopalong ", "Cassidy ", 200L), "firstThread");
----------------------------------------------------------------
16.2 管理线程
当两个线程共享公有资源时,就要保证一个线程使用资源时,另一个线程不能修改资源。 同步处理。
同步处理: 同步方法 | 同步语句块
同步方法,可以使一个类对象的方法的子集(或者全部方法)互斥。
class MyClass{ synchronized public void method1(){ } synchronized public void method2(){ } public void method3(){ } }
如果在实际运行时,MyClass 的对象有obj1,obj2。当执行obj1.method1()时,不能执行obj1.method2()。但对于obj2执行method1还是method2没有关系。
即,此同步处理是控制对同一对象的并发访问。不同对象使用同步实例方法是彼此独立的。
如果对类的静态方法用同步处理,那么在任何时候该类的这些静态方法只有一个可以执行。
将“业务”对象交给“银行”,由“银行”来处理。
业务类:将帐户,业务类型,交易总额初始化一个业务对象。
帐户类:将帐号,帐户余额初始化帐户。
职员类:指明其所在的银行,为的是将业务提交给银行。实现了Runnable接口
银行操作类:只需要一个main方法
创建银行,创建两个此银行的职员,创建一个银行帐户;
创建职员的线程,并启动。
用一个for循环,创建几笔业务,职员1每次都做存款业务,职员2每次都做货歀业务。
这里银行做业务时,必须是synchronized
class Bank { synchronized public void doTransaction(Transaction transaction){ int balance = transaction.getAccount().getBalance(); switch(transaction.getTransactionType()){ case Transaction.CREDIT: try{ Thread.sleep(100); } catch (InterruptedException e){ System.out.println(e); } balance += transaction.getAmount(); break; case Transaction.DEBIT: try{ Thread.sleep(150); } catch (InterruptedException e){ System.out.println(e); } balance -= transaction.getAmount(); break; default: System.out.println("Invalid transaction"); System.exit(1); } transaction.getAccount().setBalance(balance); } } class Transaction { public static final int DEBIT = 0; public static final int CREDIT = 1; public static String[] types = {"Debit", "Credit"}; public Transaction(Account account, int transactionType, int amount){ this.account = account; this.transactionType = transactionType; this.amount = amount; } public Account getAccount(){ return account; } public int getTransactionType(){ return transactionType; } public int getAmount(){ return amount; } public String toString(){ return types[transactionType] + " A/C: " + " :$" + amount; } private Account account; private int amount; private int transactionType; } public class Account { public Account(int accountNumber, int balance){ this.accountNumber = accountNumber; this.balance = balance; } public int getBalance(){ return balance; } public void setBalance(int balance) { this.balance = balance; } public int getAccountNumber() { return accountNumber; } public String toString() { return "A//C No. " + accountNumber+" :$"+balance; } private int balance; private int accountNumber; } public class Clerk implements Runnable { public Clerk(Bank theBank){ this.theBank = theBank; inTray = null; } public void doTransaction(Transaction transaction){ inTray = transaction; } public void run(){ while(true){ while(inTray == null){ try{ Thread.sleep(150); } catch (InterruptedException e){ System.out.println(e); } } theBank.doTransaction(inTray); inTray = null; } } public boolean isBusy(){ return inTray != null; } private Bank theBank; private Transaction inTray; } import java.util.Random; public class BankOperation { public static void main(String[] args){ int initialBalance = 500; int totalCredits = 0; int totalDebits = 0; int transactionCount = 20; //Create the account, the bank, and the clerks... Bank theBank = new Bank(); Clerk clerk1 = new Clerk(theBank); Clerk clerk2 = new Clerk(theBank); Account account = new Account(1, initialBalance); //Create the threads for the clerks as daemon, and start them off Thread clerk1Thread = new Thread(clerk1); Thread clerk2Thread = new Thread(clerk2); clerk1Thread.setDaemon(true); clerk2Thread.setDaemon(true); clerk1Thread.start(); clerk2Thread.start(); //Generate the transactions of each type and pass to the clerks Random rand = new Random(); Transaction transaction; int amount = 0; for(int i = 0; i<=transactionCount; i++){ amount = 50 + rand.nextInt(26); transaction = new Transaction(account, Transaction.CREDIT, amount); totalCredits += amount; while(clerk1.isBusy()){ try{ Thread.sleep(25); } catch(InterruptedException e){ System.out.println(e); } } clerk1.doTransaction(transaction); amount = 30 + rand.nextInt(31); transaction = new Transaction(account, Transaction.DEBIT, amount); totalDebits += amount; while(clerk2.isBusy()){ try{ Thread.sleep(25); } catch(InterruptedException e){ System.out.println(e); } } clerk2.doTransaction(transaction); } //Wait until both clerks are done while(clerk1.isBusy() || clerk2.isBusy()){ try{ Thread.sleep(25); } catch(InterruptedException e){ System.out.println(e); } } //Now output the results System.out.println( "Original balance: $"+initialBalance +"n"+ "Total credits: $"+totalCredits+"n"+ "Total debits: $"+totalDebits+"n"+ "Final balance: $"+account.getBalance()+"n"+ "Should be: $"+(initialBalance+totalCredits - totalDebits)); } } ======================================= class Bank { // synchronized public void doTransaction(Transaction transaction){ // int balance = transaction.getAccount().getBalance(); switch(transaction.getTransactionType()){ case Transaction.CREDIT: synchronized(transaction.getAccount()){ System.out.println("Start credit of "+ transaction.getAccount() +" amount: "+ transaction.getAmount()); int balance = transaction.getAccount().getBalance(); try{ Thread.sleep(100); } catch (InterruptedException e){ System.out.println(e); } balance += transaction.getAmount(); transaction.getAccount().setBalance(balance); System.out.println(" End credit of "+ transaction.getAccount()+" amount: "+ transaction.getAmount()); } break; case Transaction.DEBIT: synchronized(transaction.getAccount()){ System.out.println("Start debit of "+ transaction.getAccount()+" amount: "+ transaction.getAmount()); int balance = transaction.getAccount().getBalance(); try{ Thread.sleep(150); } catch (InterruptedException e){ System.out.println(e); } balance -= transaction.getAmount(); transaction.getAccount().setBalance(balance); System.out.println(" End debit of "+ transaction.getAccount()+" amount "+ transaction.getAmount()); } break; default: System.out.println("Invalid transaction"); System.exit(1); } } } import java.util.Random; public class BankOperationMultiAccount { public static void main(String[] args){ int[] initialBalance = {500,800}; int[] totalCredits = new int[initialBalance.length]; int[] totalDebits = new int[initialBalance.length]; int transactionCount = 20; //Create the account, the bank, and the clerks... Bank theBank = new Bank(); Clerk clerk1 = new Clerk(theBank); Clerk clerk2 = new Clerk(theBank); // Account account = new Account(1, initialBalance); Account[] accounts = new Account[initialBalance.length]; for(int i =0; i<initialBalance.length; i++){ accounts[i] = new Account(i+1, initialBalance[i]); totalCredits[i] = totalDebits[i] = 0; } //Create the threads for the clerks as daemon, and start them off Thread clerk1Thread = new Thread(clerk1); Thread clerk2Thread = new Thread(clerk2); clerk1Thread.setDaemon(true); clerk2Thread.setDaemon(true); clerk1Thread.start(); clerk2Thread.start(); //Generate the transactions of each type and pass to the clerks Random rand = new Random(); Transaction transaction; int amount = 0; int select = 0; for(int i = 0; i<=transactionCount; i++){ select = rand.nextInt(accounts.length); amount = 50 + rand.nextInt(26); transaction = new Transaction(accounts[select], Transaction.CREDIT, amount); totalCredits[select] += amount; while(clerk1.isBusy()){ try{ Thread.sleep(25); } catch(InterruptedException e){ System.out.println(e); } } clerk1.doTransaction(transaction); select = rand.nextInt(accounts.length); amount = 30 + rand.nextInt(31); transaction = new Transaction(accounts[select], Transaction.DEBIT, amount); totalDebits[select] += amount; while(clerk2.isBusy()){ try{ Thread.sleep(25); } catch(InterruptedException e){ System.out.println(e); } } clerk2.doTransaction(transaction); } //Wait until both clerks are done while(clerk1.isBusy() || clerk2.isBusy()){ try{ Thread.sleep(25); } catch(InterruptedException e){ System.out.println(e); } } //Now output the results for(int i=0; i<accounts.length; i++){ System.out.println( "Account Number:"+accounts[i].getAccountNumber() + "n"+ "Original balance: $"+initialBalance[i] +"n"+ "Total credits: $"+totalCredits[i]+"n"+ "Total debits: $"+totalDebits[i]+"n"+ "Final balance: $"+accounts[i].getBalance()+"n"+ "Should be: $"+(initialBalance[i]+totalCredits[i] - totalDebits[i])+"n"); } } } ===================================================================== ===================================================================== public class Clerk implements Runnable { public Clerk(Bank theBank){ this.theBank = theBank; inTray = null; } synchronized public void doTransaction(Transaction transaction){ // inTray = transaction; while(inTray != null){ try{ wait(); } catch (InterruptedException e){ System.out.println(e); } } inTray = transaction; notifyAll(); } synchronized public void run(){ while(true){ while(inTray == null){ try{ // Thread.sleep(150); wait(); } catch (InterruptedException e){ System.out.println(e); } } theBank.doTransaction(inTray); inTray = null; notifyAll(); } } synchronized public void isBusy(){ while(inTray != null){ try{ wait(); } catch(InterruptedException e){ System.out.println(e); } } return; // return inTray != null; } private Bank theBank; private Transaction inTray; } import java.util.Random; public class BankOperationMultiAccount { public static void main(String[] args){ int[] initialBalance = {500,800}; int[] totalCredits = new int[initialBalance.length]; int[] totalDebits = new int[initialBalance.length]; int transactionCount = 20; //Create the account, the bank, and the clerks... Bank theBank = new Bank(); Clerk clerk1 = new Clerk(theBank); Clerk clerk2 = new Clerk(theBank); // Account account = new Account(1, initialBalance); Account[] accounts = new Account[initialBalance.length]; for(int i =0; i<initialBalance.length; i++){ accounts[i] = new Account(i+1, initialBalance[i]); totalCredits[i] = totalDebits[i] = 0; } //Create the threads for the clerks as daemon, and start them off Thread clerk1Thread = new Thread(clerk1); Thread clerk2Thread = new Thread(clerk2); clerk1Thread.setDaemon(true); clerk2Thread.setDaemon(true); clerk1Thread.start(); clerk2Thread.start(); //Generate the transactions of each type and pass to the clerks Random rand = new Random(); Transaction transaction; int amount = 0; int select = 0; for(int i = 0; i<=transactionCount; i++){ select = rand.nextInt(accounts.length); amount = 50 + rand.nextInt(26); transaction = new Transaction(accounts[select], Transaction.CREDIT, amount); totalCredits[select] += amount; clerk1.doTransaction(transaction); select = rand.nextInt(accounts.length); amount = 30 + rand.nextInt(31); transaction = new Transaction(accounts[select], Transaction.DEBIT, amount); totalDebits[select] += amount; clerk2.doTransaction(transaction); } //Wait until both clerks are done clerk1.isBusy(); clerk2.isBusy(); //Now output the results for(int i=0; i<accounts.length; i++){ System.out.println( "Account Number:"+accounts[i].getAccountNumber() + "n"+ "Original balance: $"+initialBalance[i] +"n"+ "Total credits: $"+totalCredits[i]+"n"+ "Total debits: $"+totalDebits[i]+"n"+ "Final balance: $"+accounts[i].getBalance()+"n"+ "Should be: $"+(initialBalance[i]+totalCredits[i] - totalDebits[i])+"n"); } } }
同步语句块
见上面thread代码中“==============”以下的代码,因为只改了Bank,新增了BankOperationMultiAccount
死锁
thread1 run(){ synchronized(theObject){ sleep(1000); theOtherObject.method2(); } } thread2 run(){ synchronized(theOtherObject){ sleep(1000); theObject.method1(); } }
线程间通信
wait() | notify() | notifyAll()
Object类定义了以一3个方法,但只能在同步方法或同步代码块中调用这些方法。
synchronized(anObject){ while(condition-not-met) anObject.wait(); }
当调用wait时,线程会将操作挂起,直到同步于同一对象的另外某个线程调用了notify方法。
代码在thread代码
=============================
=============================
后面
在Clerk中同步方法doTransaction,但是这个方法运行在主线程中,若其wait,其实将主线程挂起,只有在run中的wait才是将clerk1对象挂起。