Java网络编程——线程

一、为什么要使用多线程

1、耗时操作使用线程。可有效提高应用程序的响应

2、并行操作需要使用线程,如C/S服务器端并发响应请求

3、多CPU系统中,采用多线程提高CPU利用率

4、改善程序结构

二、使用线程时注意事项

1、不同的线程共享相同的内存,一个线程可能破坏另一个线程使用的变量或数据结构

2、十分注意资源的使用,防止产生死锁

三、运行线程的方法

1、派生Thread

重写run方法

复制代码
import java.io.FileInputStream;
import java.io.IOException;
import java.security.*;


public class TestThread extends Thread{
    private String fileName;
    
    public TestThread(String fileName) {
        this.fileName = fileName;
    }

    
    public void run() {
        // TODO Auto-generated method stub
        try{
            FileInputStream in = new FileInputStream(fileName);
            MessageDigest sha = MessageDigest.getInstance("SHA-256");
            DigestInputStream din = new DigestInputStream(in, sha);    
            while(din.read() != -1);
            din.close();
            byte[] digest = sha.digest();
            
            StringBuilder result = new StringBuilder(fileName);
            result.append(":");
            result.append(digest);
            System.out.println(result);
        }catch(IOException e){
            System.out.println(e);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }


    public static void main(String[] args) {
        // TODO Auto-generated method stub
        String fileName = new String("D:\\workspace5\\TestThread\\file.txt");
        Thread t = new TestThread(fileName);
        t.start();
        
    }

}
复制代码

2、实现Runnable接口

复制代码
import java.io.FileInputStream;
import java.io.IOException;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;


public class TestRunnable implements Runnable{
    private String fileName;
    
    public TestRunnable(String fileName) {
        this.fileName = fileName;
    }
    
    public void run() {
        // TODO Auto-generated method stub
        try{
            FileInputStream in = new FileInputStream(fileName);
            MessageDigest sha = MessageDigest.getInstance("SHA-256");
            DigestInputStream din = new DigestInputStream(in, sha);    
            while(din.read() != -1);
            din.close();
            byte[] digest = sha.digest();
            
            StringBuilder result = new StringBuilder(fileName);
            result.append(":");
            result.append(digest);
            System.out.println(result);
        }catch(IOException e){
            System.out.println(e);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        TestRunnable tr = new TestRunnable("D:\\workspace5\\TestThread\\file.txt");
        Thread t = new Thread(tr);
        t.start();
    }

}
复制代码

 四、从线程返回结果

1、轮询

主线程定期轮询,查看标志位。

复制代码
import java.io.FileInputStream;
import java.io.IOException;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;


public class ReturnDigest extends Thread{
    
    private String mFileName;
    private byte[] mDigest;
    
    public ReturnDigest(String mFileName) {
        this.mFileName = mFileName;
    }

    
    public void run() {
        // TODO Auto-generated method stub
        try{
            FileInputStream in = new FileInputStream(mFileName);
            MessageDigest sha = MessageDigest.getInstance("SHA-256");
            DigestInputStream din = new DigestInputStream(in, sha);    
            while(din.read() != -1);
            din.close();
            mDigest = sha.digest();
        }catch(IOException e){
            System.out.println(e);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }
    
    public byte[] getDigest() {
        return mDigest;
    }
}
复制代码

 

复制代码
public class ReturnDigestUserInterface {

    public static void main(String[] args) {
        // calculate abstract
        String mFileName = new String("D:\\workspace5\\TestThread\\file.txt");
        ReturnDigest rd = new ReturnDigest(mFileName);
        rd.start();
        
        while(true){//主线程轮询查看标志位digest
            byte[] digest = rd.getDigest();
            if(digest != null){
                StringBuilder result = new StringBuilder(mFileName);
                result.append(":");
                result.append(digest);
                System.out.println(result);
                break;
            }
        }
        
    }

}
复制代码

2、回调

轮询是无限循环,判断标志位,开销较大。回调:子线程快结束时调用主线程的方法,将结果传回主线程。

复制代码
import java.io.FileInputStream;
import java.io.IOException;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;


public class CallbackDigest implements Runnable{

private String mFileName;
    
    public CallbackDigest(String mFileName) {
        this.mFileName = mFileName;
    }
    
    public void run() {
        // TODO Auto-generated method stub
        try{
            FileInputStream in = new FileInputStream(mFileName);
            MessageDigest sha = MessageDigest.getInstance("SHA-256");
            DigestInputStream din = new DigestInputStream(in, sha);    
            while(din.read() != -1);
            din.close();
            byte[] digest = sha.digest();
            CallbackDigestUserInterface.receiveDigest(digest, mFileName);//回调主线程中的方法
            
        }catch(IOException e){
            System.out.println(e);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }

}
复制代码

 

复制代码
public class CallbackDigestUserInterface {

    public static void main(String[] args) {
        // 计算摘要
        CallbackDigest cb = new CallbackDigest("D:\\workspace5\\TestThread\\file.txt");
        Thread t = new Thread(cb);
        t.start();

    }
    public static void receiveDigest(byte[] digest, String mFileName) {
        StringBuilder result = new StringBuilder(mFileName);
        result.append(":");
        result.append(digest);
        System.out.println(result);
        
    }

}
复制代码

3、回调实例方法

回调的类有其回调对象的一个引用

复制代码
import java.io.FileInputStream;
import java.io.IOException;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;


public class InstanceCallbackDigest implements Runnable{
    
    private String mFileName;
    private InstanceCallbackDigestUserInstance mCallback;//回调对象的一个引用
    
    
    
    public InstanceCallbackDigest(String mFileName,
            InstanceCallbackDigestUserInstance mCallback) {
        super();
        this.mFileName = mFileName;
        this.mCallback = mCallback;
    }


    public void run() {
        // TODO Auto-generated method stub
        try{
            FileInputStream in = new FileInputStream(mFileName);
            MessageDigest sha = MessageDigest.getInstance("SHA-256");
            DigestInputStream din = new DigestInputStream(in, sha);    
            while(din.read() != -1);
            din.close();
            byte[] digest = sha.digest();
            mCallback.receiveDigest(digest);//回调主线程中的方法
            
        }catch(IOException e){
            System.out.println(e);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }

}
复制代码

 

复制代码
public class InstanceCallbackDigestUserInstance {

    private String mFileName;
    private byte[] mDigest;
    
    
    public InstanceCallbackDigestUserInstance(String mFileName) {
        super();
        this.mFileName = mFileName;
    }

    public void calculate(){
        InstanceCallbackDigest ic = new InstanceCallbackDigest(mFileName, this);
        Thread t = new Thread(ic);
        t.start();
    }
    
    void receiveDigest(byte[] digest) {
        this.mDigest = digest;
        System.out.println(this);
    }

    public static void main(String[] args) {
        InstanceCallbackDigestUserInstance i = new InstanceCallbackDigestUserInstance("D:\\workspace5\\TestThread\\file.txt");
        i.calculate();
    }
}
复制代码

4、Future、Callable和Executor

隐藏异步性的回调。

(1)创建一个ExecutorService,它会根据需要给你创建相应的线程。

(2)向ExecutorService提交Callable任务,每一个Callable会分别得到一个Future

(3)可向Future请求得到的结果

复制代码
import java.util.concurrent.Callable;


public class FindMaxTask implements Callable<Integer>{
    private int [] data;
    private int start;
    private int end;
    
    
    public FindMaxTask(int[] data, int start, int end) {
        super();
        this.data = data;
        this.start = start;
        this.end = end;
    }


    public Integer call() throws Exception {
        int max = Integer.MIN_VALUE;
        for(int i = start; i< end; i++){
            if(data[i] > max){
                max = data[i];
            }
        }
        return max;
    }

}
复制代码
复制代码
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;


public class MultithreadedMaxFinder {
    
    public static int max(int data[]) throws InterruptedException, ExecutionException{
        if(data.length == 1){
            return data[0];
        }
        if(data.length == 0){
            throw new IllegalArgumentException();
        }
        
        //划分两个任务
        FindMaxTask task1 = new FindMaxTask(data, 0, data.length/2);
        FindMaxTask task2 = new FindMaxTask(data,data.length/2 , data.length);
        
        //创建ExecutorService
        ExecutorService services = Executors.newFixedThreadPool(2);
        Future<Integer> future1 = services.submit(task1);
        Future<Integer> future2 = services.submit(task2);
        
        return Math.max(future1.get(), future2.get());
    }
    
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        int[] data = {68,3,5,9,14,37,45,1};
        System.out.println(max(data));
    }

}
复制代码

 五、同步

指定一个共享资源只能由一个线程独占访问来执行特定的语句序列

1、同步块

把需要同步的语句放入到同步块

synchronized(System.out){//对System.out对象同步
            result.append(":");
            result.append(digest);
            System.out.println(result);
        }

2、同步方法

复制代码
public synchronized void writeEntry(String message){
        Date d = new Date();
        out.write(d.toString());
        out.write('\t');
        out.write(message);
        out.write('\r\n');
    }
复制代码

3、同步的替代方法

(1)尽量使用局部变量而不是字段,局部变量不存在同步问题,包括方法的参数

(2)利用类的不可变性,private和final

(3)将非线程安全的类作为线程安全的类的一个私有字段

(4)对于Collection和List,有线程安全版本,Collections.synchronizedSet(foo)/Collections.synchronizedList(foo)/Collections.synchronizedMap(foo)

六、死锁

不必要的同步常常会导致死锁,要保证同步块尽量小,尽量不要一次同步多个对象。

七、线程调度

主要有两种线程调度机制:抢占式和协作式。每个线程都有一个优先级,Java中,10是最高优先级,0是最低优先级,5是默认优先级。

为了让其他线程有机会运行,线程有10中方式可以暂停或指示它准备暂停。

1、对I/O阻塞

当线程停下来等待它没有的资源时,就会发生阻塞。常见的阻塞有I/O阻塞和对锁的阻塞。

2、对同步对象阻塞

3、放弃

显示地放弃控制权,通过调用Thread.yield()方法。注意:放弃不会释放这个线程拥有的锁,在线程放弃时不应做任何同步。

4、休眠

不管是否是其他线程准备运行,休眠线程都会暂停。通过调用Thread.sleep()方法。注意:进入休眠的线程拥有其已经获得的锁,避免在同步方法和同步块中做休眠操作

5、连接另一个线程

当一个线程需要另一个线程的结果时,常常使用join()方法。使得一个线程在继续执行前等待另一个线程结束。

复制代码
public class TestJoinSortThread extends Thread{
    private double[] array;

    public TestJoinSortThread(double[] array) {
        this.array = array;
    }

    @Override
    public void run() {
        for(int i = 0; i < array.length; i++){
            for(int j = i; j<array.length; j++){
                if(array[i] > array[j]){
                    double temp = array[i];
                    array[i] = array[j];
                    array[j] = temp;
                }
            }
        }
            
    }
}
复制代码

 

复制代码
public class TestJoin {

    public static void main(String[] args) {
        double[] array = new double[10000];
        //随机生成数组
        for(int i = 0; i < array.length; i++){
            array[i] = Math.random();
        }
        
        TestJoinSortThread st = new TestJoinSortThread(array);
        st.start();
        
        try{
            st.join();//连接
            System.out.println("MIN:" + array[array.length - 1]);
            System.out.println("MAX:" + array[0]);
            System.out.println("Middle:" + array[array.length/2]);
        }catch(InterruptedException e){
            
        }
    }

}
复制代码

6、等待一个对象

7、结束

8、被更高优先级线程抢占

9、被挂起

10、停止

posted on 2015-09-15 11:18  Ceeport  阅读(143)  评论(0)    收藏  举报

导航