java并发编程基础---Sky

1.线程及启动和终止

1.1 线程 -进程/优先级

   操作系统调度的最小单元是线程,线程是轻量级进程。

   线程优先级由setPriority(int)方法来设置,默认优先级是5,等级1~10.等级越高分的时间片越多。

1.2 线程的状态

  new 初始化 》》Runable 运行》》Blocked阻塞 》》Wating等待》》 time_Wating超时等待》》 temerinated终止状态。

1.3 Daemon辅助线程

  主线程终止后,辅助线程也就结束。thread.setDaemon(true)设置在线程开始之前。

1.4 过期suspend() , resume(), stop()为啥不建议使用?

  suspend()调用后太霸道,不释放占有资源,而是抱着占有资源去睡觉,这样容易死锁。站着茅坑不拉屎。

  resume()、stop()不保证线程资源正常释放,那要你们何用?

  安全的终止线程:有中断操作,和自定义cancel()方法。

 1 package Thread;
 2 
 3 import java.util.concurrent.TimeUnit;
 4 
 5 /**
 6  * Created by Sky on 2016/9/22.
 7  * @author xiaoyongyong
 8  */
 9 public class Shutdown {
10     public static void main(String[] args) throws InterruptedException {
11         Runner one = new Runner();
12         Thread countThread = new Thread(one,"CountThread");
13         countThread.start();
14         TimeUnit.SECONDS.sleep(1);
15         countThread.interrupt();
16 
17         Runner two = new Runner();
18         countThread = new Thread(two,"CountThread");
19         countThread.start();
20         TimeUnit.SECONDS.sleep(1);
21         two.cancle();
22     }
23 
24     private static class Runner  implements Runnable{
25         private  long i;
26         private volatile boolean on =true;
27         @Override
28         public void run() {
29             while (on && !Thread.currentThread().isInterrupted()){
30                 i++;
31             }
32             System.out.println("Count i ="+ i);
33         }
34         public void cancle(){
35             on = false;
36         }
37     }
38 }
View Code

2. 线程之间通信

2.1 volatile 和 synchronized 关键字。

  volatile:它能保证所有线程对变量访问的可见性,即某线程对定义变量的修改,其他线程可见。谨慎使用,过多使用会降低程序运行效率。

  syncchronized:保证只有一个线程能对其定义的变量修改。保证其变量访问的可见性和排他性。

2.2 通知/等待机制

  可以确保及时性和降低开销。

  相关方法:notify()、nitifyAll()、wait()、wait(long)、wait(long,int)。

  注意点:1)使用notify()、nitifyAll()、wait()时需要先对调用对象加锁。2)notify()、nitifyAll()方法调用后,等待线程依旧不会从wait()方法返回,

  需要调用notify()、nitifyAll()方法的线程,释放锁之后,等待线程才有机会从wait()返回。等待队列-》同步队列。3)wait()方法返回的前提是获取对象锁。

这种机制可以运用在生产者-消费者模式中。

 1 package Thread;
 2 
 3 import java.text.SimpleDateFormat;
 4 import java.util.Date;
 5 import java.util.concurrent.TimeUnit;
 6 
 7 /**
 8  * Created by Sky on 2016/9/22.
 9  *
10  * @author xiaoyongyong
11  */
12 public class WaitNotify {
13     static boolean flag = true;
14     static final Object lock = new Object();
15 
16     public static void main(String[] args) throws Exception {
17         Thread waitTread = new Thread(new Wait(), "WaitTread");
18         waitTread.start();
19         TimeUnit.SECONDS.sleep(1);
20 
21         Thread notifyTread = new Thread(new NotifyTread(), "NotifyTread");
22         notifyTread.start();
23     }
24 
25     private static class Wait implements Runnable {
26         @Override
27         public void run() {
28             synchronized (lock) {
29                 while (flag) {
30                     try {
31                         System.out.println(Thread.currentThread() + " flag is true.wait. " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
32                         lock.wait();
33                     } catch (InterruptedException e) {
34                         e.printStackTrace();
35                     }
36                 }
37                 System.out.println(Thread.currentThread() + " flag is true.running. " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
38             }
39         }
40     }
41 
42     private static class NotifyTread  implements Runnable {
43         @Override
44         public void run() {
45             synchronized (lock){
46                 System.out.println(Thread.currentThread() + " hold lock.notify. " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
47                 lock.notifyAll();
48                 flag = false;
49                 try {
50                     TimeUnit.SECONDS.sleep(2);
51                 } catch (InterruptedException e) {
52                     e.printStackTrace();
53                 }
54             }
55             synchronized (lock) {
56                 System.out.println(Thread.currentThread() + " hold lock.again.sleep " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
57                 try {
58                     TimeUnit.SECONDS.sleep(2);
59                 } catch (InterruptedException e) {
60                     e.printStackTrace();
61                 }
62             }
63         }
64     }
65 }
View Code

返回结果:

Thread[WaitTread,5,main] flag is true.wait. 22:03:45
Thread[NotifyTread,5,main] hold lock.notify. 22:03:46
Thread[NotifyTread,5,main] hold lock.again.sleep 22:03:48
Thread[WaitTread,5,main] flag is true.running. 22:03:50

2.3 管道输入/输出流

  主要用于线程之间的数据传输,传输媒介是内存,有PipedOutputStream/PipedInputStream(面向字节)  和PipedReader/PipedWriter(面向字符)。

 1 package Thread;
 2 
 3 import java.io.IOException;
 4 import java.io.PipedReader;
 5 import java.io.PipedWriter;
 6 
 7 /**
 8  * Created by Sky on 2016/9/22.
 9  * @author xiaoyongyong
10  */
11 public class Piped {
12     public static void main(String[] args) throws IOException {
13         PipedWriter out = new PipedWriter();
14         PipedReader in = new PipedReader();
15         out.connect(in);
16         Thread printThread = new Thread(new Print(in), "PringThread");
17         printThread.start();
18 
19         int receive;
20         try {
21             while ((receive = System.in.read()) != -1) {
22                 out.write(receive);
23             }
24         } finally {
25             out.close();
26         }
27     }
28 
29     private static class Print implements Runnable {
30         private PipedReader in;
31         public Print(PipedReader in) {
32             this.in = in;
33         }
34         @Override
35         public void run() {
36             int receive;
37             try {
38                 while ((receive = in.read()) != -1) {
39                     System.out.print((char) receive);
40                 }
41             } catch (IOException e) {
42                 e.printStackTrace();
43             }
44         }
45     }
46 }
View Code

输入一串字符串,按enter后,将原样输出。管道输入输出流必须先连接才可复制,即connect()。

2.4 Thread.join()的使用

  当线程A等待thread线程终止之后,才从thread.join()返回。

join方法顾名思义 就是往线程中添加东西的;join方法可以用于临时加入线程,一个线程在运算过程中,如果满足于条件,我们可以临时加入一个线程,让这个线程运算完,另外一个线程再继续运行。

Thread,yeld()和Thread.sleep()的区别?

  hread.yield()方法暂停当前正在执行的线程对象,并执行其他线程。也就是交出CPU一段时间(其他同样的优先级或者更高优先级的线程可以获取到运行的机会);不会释放锁资源。

  而Thread.sleep()方法使当前线程进入停滞状态,所以执行sleep()的线程在指定的时间内肯定不会执行, 同时sleep函数不会释放锁资源;sleep可使优先级低的线程得到执行的机会,当然也可以让同优先级和高优先级的线程有执行的机会。

这两个的区别在于yield只能是同级,或者高级优先执行,而sleep可以低级,同级都可以有优先执行机会。

 

2.5 ThreadLocal的使用

线程变量,是一个以TreadLocal对象为键,任意对象为值得存储结构。

2.6 线程池技术及示例。

以下是线程池接口的定义和实现:

package Thread;

/**
 * Created by asus on 2016/9/27.
 */
public interface ThreadPool<Job extends Runnable> {
    void execute(Job job);
    void shutdown();
    void addWorkers(int num);
    void removeWoker(int num);
    int getJobSize();
}
View Code
package Thread;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;

/**
 * Created by asus on 2016/9/27.
 *
 * @author xiaoyongyong
 */
public class DefaultThreadPool<Job extends Runnable> implements ThreadPool<Job> {
    private static final int MAX_WORKER_NUMBERS = 10;
    private static final int DEFAULT_WORKER_NUMBERS = 5;
    private static final int MIN_WORKER_NUBERS = 1;
    private final LinkedList<Job> jobs = new LinkedList<Job>();
    private final List<Worker> workers = Collections.synchronizedList(new ArrayList<Worker>());
    private int workerNum = DEFAULT_WORKER_NUMBERS;
    private AtomicLong threadNum = new AtomicLong();

    public DefaultThreadPool() {
        initializeWorker(DEFAULT_WORKER_NUMBERS);
    }

    private void DefaultThreadPool(int num) {
        workerNum = num > MAX_WORKER_NUMBERS ? MAX_WORKER_NUMBERS : num < MIN_WORKER_NUBERS ? MAX_WORKER_NUMBERS : num;
        initializeWorker(workerNum);
    }

    @Override
    public void execute(Job job) {
        if (job != null) {
            synchronized (jobs) {
                jobs.add(job);
                jobs.notify();
            }
        }
    }

    @Override
    public void shutdown() {
        for (Worker worker : workers) {
            worker.shutdown();
        }
    }

    @Override
    public void addWorkers(int num) {
        synchronized (jobs) {
            if (num + this.workerNum > MAX_WORKER_NUMBERS) {
                initializeWorker(num);
                this.workerNum += num;
            }
        }
    }

    @Override
    public void removeWoker(int num) {
        synchronized (jobs) {
            if (num >= this.workerNum) {
                throw new IllegalArgumentException("beyond workerNum");
            }
            int count = 0;
            while (count < num) {
                Worker worker = workers.get(count);
                if (workers.remove(worker)) {
                    worker.shutdown();
                    count++;
                }
            }
            this.workerNum -= count;
        }
    }

    @Override
    public int getJobSize() {
        return jobs.size();
    }

    private void initializeWorker(int num) {
        for (int i = 0; i < num; i++) {
            Worker worker = new Worker();
            workers.add(worker);
            Thread threadWorker = new Thread(worker, "ThreadPool-Worker-" + threadNum.incrementAndGet());
            threadWorker.start();
        }
    }


    class Worker implements Runnable {
        private volatile boolean running = true;

        @Override
        public void run() {
            while (running){
                Job job = null;
                synchronized (jobs){
                    while (jobs.isEmpty()){
                        try {
                            jobs.wait();
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                            e.printStackTrace();
                            return;
                        }
                    }
                    job = jobs.removeFirst();
                }
                if(job != null){
                    job.run();
                }
            }
        }

        public void shutdown() {
            running = false;
        }
    }
}
View Code

2.7 基于县此次技术的简单Web服务器

这个服务器使用main线程不断接受客户端Socket的连接,将连接以及请求交给线程池处理,这样使得Web服务器能够同同时处理多个客户端请求。

 

 

       

 

 

 

 

 

posted @ 2016-09-21 23:03  Sky—yong  阅读(276)  评论(0编辑  收藏  举报