[Java2 入门经典]第16章 线程

网上对线程的总结: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;

}
setDaemon

将线程设置到执行状态将线程设置到中止状态

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;

}
runnable

线程的名称: 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

同步语句块

见上面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对象挂起。

原文地址:https://www.cnblogs.com/jimwind/p/2755834.html