线程和线程池

一、Thread 类
  构造方法:Thread():创建新的线程
    Thread(String name):创建新的线程并指定改线程名
    Thread(Runnable runnable):创建新的线程并传入指定任务
  常用方法:对象.start():开始线程并执行任务
    run():要执行的任务
    sleep(long millis):暂停多少毫秒后执行
  实现过程:
    1、自定义类使之继承 Thread 类
    2、重写run()方法
    3、创建自定义类对象
    4、调用start()方法

  Demo:

  自定义类

1 public class MyThread extends Thread {
2     // run方法是用来描述线程任务的
3     @Override
4     public void run() {
5         for (int i = 0; i < 100; i++) {
6             System.out.println(getName() + ":" + i);
7         }
8     }
9 }

开启线程

1     public static void main(String[] args) {
2         MyThread mt = new MyThread();
3         // 开启线程
4         mt.start();
5         
6         for (int i = 0; i < 100; i++) {
7             System.out.println( Thread.currentThread().getName()+":"+ i);
8         }
9     }

二、Runnable 接口 (创建任务对象)
  好处:创建的任务对象,可以被多次执行,Thread 自定义类执行继承,继承的单一性,但是 Runnable 接口,可以实现多实现,不再单一。
  实现过程:
    1、自定义类使之实现 Runnable 接口
    2、重写Run 方法
    3、创建 自定义类的 对象
    4、创建 Thread 对象 并传入 指定任务对象 (自定义类对象)
    5、调用 Thread 的 start() 方法,使之开始执行任务

  Demo

  自定义类

  

1 public class MyRunnable implements Runnable {
2 
3     @Override
4     public void run() {
5         for (int i = 0; i < 100; i++) {
6             System.out.println(Thread.currentThread().getName() + ":" + i);
7         }
8     }
9 }

开启线程

 

 1 public static void main(String[] args) {
 2         Thread.currentThread().setName("System");
 3         // 创建线程任务对象
 4         MyRunnable mr = new MyRunnable();
 5                 //创建线程对象,并传入任务
 6         Thread t = new Thread(mr);
 7         t.setName("YHYThread");
 8                 //开启线程
 9         t.start();
10         for (int i = 0; i < 100; i++) {
11             System.out.println(Thread.currentThread().getName() + ":" + i);
12         }
13     }


三、使用匿名内部类来实现多线程
1、使用 Thread
    new Thread(){
      重写run 方法
    }.start();

    

1 new Thread(new Runnable() {
2             public void run() {
3                 Thread.currentThread().setName("YY");
4                 for (int i = 0; i < 100; i++) {
5                     System.out.println(Thread.currentThread().getName() + ":" + i);
6                 }
7             }
8         }).start();

    


2、使用 Runnable
    Runnable r = new Runnable(){
      重写run方法
    };
    Thread t = new Thread(r);
    t.start();

    

 1 public static void main(String[] args) {
 2         Runnable r= new Runnable() {            
 3             @Override
 4             public void run() {
 5                 System.out.println("任务");
 6             }
 7         };
 8         
 9         Thread t= new Thread(r);
10         t.start();
11     } 


四、线程池
  创建线程池对象:
    ExecutorService es = Executors.newFixedThreadPool(int nThreads);//传入需要开始线程的数量。

  使用Runnable 接口实现线程池
      1、创建Runnable的任务对象 并重写 run() 方法。
      2、获取线程池对象
      3、线程池对象.submit(Runnable task);//传入要执行的任务对象
      4、关闭线程池对象 线程池对象.shutdown();

      

 1     public static void main(String[] args) {
 2 //        指定任务对象,可以使用自定义类,实现Runnable接口
 3         Runnable r = new Runnable() {
 4             @Override
 5             public void run() {
 6                 System.out.println("任务");
 7             }
 8         };
 9 
10 //        获取线程池对象
11         ExecutorService es = Executors.newFixedThreadPool(2);
12 //        指定任务
13         es.submit(r);
14 //        关闭线程池
15         es.shutdown();
16     }

    使用 Callable 接口实现线程池
      1、创建 Callable 的任务对象,并重写 call() 方法。
      2、创建线程池对象
      3、线程池对象.submit(Callable c);//传入任务对象 (Callable 对象),假如有参数,使用Future<返回值类型> 接收
      4、获取返回值 Future<返回值类型>对象.get() 获取 call() 方法的返回值
      5、关闭线程池对象

      

 1     public static void main(String[] args) throws InterruptedException, ExecutionException {
 2 //        指定任务对象,并指定返回值,可以使用自定义类,实现Callable接口
 3         Callable<String> c = new Callable<String>() {
 4             @Override
 5             public String call() throws Exception {
 6 
 7                 return "aaa";
 8             }
 9         };
10 
11 //        获取线程池对象
12         ExecutorService es = Executors.newFixedThreadPool(2);
13 //        传入指定任务并使用 Future<V> 接收返回值
14         Future<String> submit = es.submit(c);
15 //        Future<V>对象 的 get() 方法接收返回值
16         String str = submit.get();
17         System.out.println(str);
18 //        关闭线程池
19         es.shutdown();
20     }

Callable 比Runable 的好处是:可以抛异常,可以有返回值

五、线程安全
  当线程任务共享一个数据源,并对这个数据进行操作的时候,有可能出现错误数据,这个时候就要用同步代码块,或者同步方法。
    1、定义一个同步代码块

     在 线程任务 方法外 定义任意对象 例如 

      

 1 package com.oracle.demo04;
 2 
 3 
 4 public class Tickets implements Runnable {
 5 
 6 //    所有线程共享数据放到成员位置
 7     private int ticks = 100;
 8 
 9 //    创建枷锁
10     Object lock = new Object();
11     
12     @Override
13     public void run() {
14         while (true) {
15             try {
16                 Thread.sleep(500);
17             } catch (InterruptedException e) {
18                 // TODO Auto-generated catch block
19                 e.printStackTrace();
20             }
21             synchronized (lock) {
22                 if (ticks > 0) {
23                     System.out.println(Thread.currentThread().getName() + "窗口卖了第:" + ticks-- + "张票");
24                 }
25             }
26         }
27 
28     }
29 
30 }

  将有肯能影响数据的地方用 synchronized(object){ 问题代码 } 

      


   2、定义一个同步方法 用 synchronized 修饰的方法

    

 1 package com.oracle.demo04;
 2 
 3 public class Tickets2 implements Runnable {
 4 //    所有线程共享数据放到成员位置
 5     private int ticks = 100;
 6 
 7 //    创建枷锁
 8     Object lock = new Object();
 9 
10     @Override
11     public void run() {
12         while (true) {
13             try {
14                 Thread.sleep(500);
15             } catch (InterruptedException e) {
16                 // TODO Auto-generated catch block
17                 e.printStackTrace();
18             }
19             method();
20         }
21     }
22 
23     private synchronized void method() {
24 
25         if (ticks > 0) {
26             System.out.println(Thread.currentThread().getName() + "窗口卖了第:" + ticks-- + "张票");
27         }
28     }
29 }

    然后在 线程任务中调用该方法。

   

    3、使用 lock 类。控制 同步代码块  

      

 1 package com.oracle.demo04;
 2 
 3 import java.util.concurrent.locks.Lock;
 4 import java.util.concurrent.locks.ReentrantLock;
 5 
 6 public class Tickets3 implements Runnable {
 7 
 8 //    所有线程共享数据放到成员位置
 9     private int ticks = 100;
10 
11     private Lock lock = new ReentrantLock();
12 
13     @Override
14     public void run() {
15         while (true) {
16 
17             lock.lock();
18             try {
19                 Thread.sleep(500);
20             } catch (InterruptedException e) {
21                 // TODO Auto-generated catch block
22                 e.printStackTrace();
23             }
24 //            调用 lock 方法 获取锁
25             if (ticks > 0) {
26                 System.out.println(Thread.currentThread().getName() + "窗口卖了第:" + ticks-- + "张票");
27             }
28             if(ticks > 3) {
29                 System.out.println(Thread.currentThread().getName() + "窗口卖了第:" + ticks-- + "张票");
30             }
31 //            调用 unlock 方法 释放锁
32             lock.unlock();
33         }
34     }
35 
36 }
原文地址:https://www.cnblogs.com/yanghaoyu0624/p/11737068.html