多线程四种实现方式及例题

学习目标:

一周掌握 多线程四种实现方式以及用法 入门知识


学习内容:

  1. 自定义类,继承Thread ,重写run()方法
  2. 自定义类,实现Runable ,重写run()方法
  3. 线程池
  4. 自定义类,实现callable接口重写call()
  5. 总结其中的函数

学习产出:

一.自定义类,继承Thread ,重写run()方法

package rrr;
 import java.io.*;
 
 public class thread {
    public static void main(String[] args) throws IOException {
        //创建线程`
        myThread myThread = new myThread();
        myThread myThread1 = new myThread();
//        修改名字
        myThread.setName("郑");
        myThread1.setName("李");
        //启动线程
         myThread.start();
        myThread1.start();


    }
      }

package rrr;

import java.io.*;
import java.net.*;
 public class myThread extends  Thread{
  int d=0;
  @Override
  public void run() {
   for (int a=0;a<100;a++){
    if (a%2==0) {
     d=d+a;
   // 获取当前线程名字并输出
     System.out.println(Thread.currentThread().getName() + d);
    }
   }
  }
 }

二.自定义类,实现Runable ,重写run()方法

package rrr;
 import java.io.*;

 public class thread {
    public static void main(String[] args) throws IOException {
        myThread myThread = new myThread();
        //创建线程`
        Thread thread = new Thread(myThread);
        Thread thread1 = new Thread(myThread);
//        修改名字
         thread.setName("郑");
          thread1.setName("李");
        //启动线程
        thread.start();
        thread1.start();


    }
      }
package rrr;

import java.io.*;
import java.net.*;
 public class myThread implements Runnable {
  int d=0;
  @Override
  public void run() {
   for (int a=0;a<100;a++){
    if (a%2==0) {
     d=d+a;
   // 获取当前线程名字并输出
     System.out.println(Thread.currentThread().getName() + d);
    }
   }
  }
 }

三.线程池

package rrr;
 import java.io.*;
 import java.util.concurrent.*;

public class thread {
    public static void main(String[] args) throws IOException, ExecutionException, InterruptedException {
        myThread myThread = new myThread();
        //创建固态线程池
//        ExecutorService executorService = Executors.newFixedThreadPool(2);
        //创建动态线程池
        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.submit(myThread);
        executorService.submit(myThread);
        executorService.shutdown();
    }
      }

package rrr;
 import java.util.concurrent.Callable;
 public class myThread implements Runnable {
  int d=0;
   @Override
  public void run() {
   for (int a=0;a<100;a++){
    if (a%2==0) {
      System.out.println(Thread.currentThread().getName()+"     " + a);
    }
   }
  }
 }

四.自定义类,实现callable接口重写call()

特点:他可以返回线程运行的结果

package rrr;
 import java.io.*;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.FutureTask;

public class thread {
    public static void main(String[] args) throws IOException, ExecutionException, InterruptedException {
        myThread myThread = new myThread();
        //创建FutureTask结果集对象
        FutureTask<Integer> integerFutureTask = new FutureTask<>(myThread);
        //创建线程`
        Thread thread = new Thread(integerFutureTask);
        //        修改名字
         thread.setName("线程一:");
        //启动线程
        thread.start();
        //获取线程的结果集
       Integer integer = integerFutureTask.get();
        System.out.println(integer);
   }
      }

package rrr;
 import java.util.concurrent.Callable;
 public class myThread implements Callable<Integer> {
  int d=0;
 @Override
 public Integer call()  {
  for (int a=0;a<100;a++){
   if (a%2==0) {
    d=d+a;
    // 获取当前线程名字并输出
     System.out.println(Thread.currentThread().getName() + d);
   }
  }
  return d;
 }
}

例题:

1.卖票程序1,使用乐观锁,100张,票三个窗口卖

package rrr;
 import java.io.*;
 import java.net.DatagramPacket;
 import java.net.DatagramSocket;
 import java.net.InetAddress;
 import java.net.Socket;
 import java.util.concurrent.*;

public class thread {
    public static void main(String[] args) {
       myThread myThread=new myThread();
        myThread myThread1=new myThread();
        myThread myThread2=new myThread();

        myThread.setName("窗口一");
        myThread1.setName("窗口二");
        myThread2.setName("窗口三");
        myThread.start();
        myThread1.start();
        myThread2.start();



    }
}

package rrr;


 public class myThread  extends  Thread{
//    表示这个类所有对象都共享a
     public static int a=0;
     //同步锁对象一定要唯一
//     static   Object object=new Object();
      @Override
      public  void  run() {
       //同步代码块
     while(true){
      //可以是类名class,字节码文件对象,文件是唯一的
     synchronized (myThread.class){
//      synchronized (object){
      if (a<100){
       try {
        Thread.sleep(100);
       } catch (InterruptedException e) {
        e.printStackTrace();
       }
       a++;
       System.out.println(Thread.currentThread().getName()+"卖了"+a);
      }else {
       break;
      }
     }


     }}}

1.卖票程序1,使用悲观锁,100张,票三个窗口卖

package rrr;
 import java.io.*;
 import java.net.DatagramPacket;
 import java.net.DatagramSocket;
 import java.net.InetAddress;
 import java.net.Socket;
 import java.util.concurrent.*;

public class thread {
    public static void main(String[] args) {
       myThread myThread=new myThread();
        myThread myThread1=new myThread();
        myThread myThread2=new myThread();

        myThread.setName("窗口一");
        myThread1.setName("窗口二");
        myThread2.setName("窗口三");
        myThread.start();
        myThread1.start();
        myThread2.start();



    }
}
package rrr;


import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class myThread  extends  Thread{
//    表示这个类所有对象都共享a
    static int a1=0;
     //同步锁对象一定要唯一
//     static   Object object=new Object();
      //创建悲观锁对象
      static   Lock d1= new ReentrantLock();
      @Override
      public  void  run() {
       //同步代码块
     while(true){
      //上锁
      d1.lock();
       try {
        //等于100退出循环
       if (a1==100){
           break;
        }else {
              a1++;
              System.out.println(Thread.currentThread().getName()+"卖了"+a1);
             }
                   } catch (Exception e) {
                  e.printStackTrace();
                }
      finally {
        //无论如何也要开锁
             d1.unlock();
             //开完锁后睡0.01秒
            try {
            Thread.sleep(10);
            } catch (InterruptedException e) {
            e.printStackTrace();
        }
       }


     }}}

2.生产者消费者,生产者进行生产奶,消费者消费奶,利用线程进行等待唤醒(因为篇幅长,增加可观性,就不进行导包了)

实现方式一:

 public class text {
    public static void main(String[] args) {
     box box = new box();
     milkWork milkWork = new milkWork(box);
     perSon perSon = new perSon(box);
     Thread a=new Thread(milkWork);
     Thread d=new Thread(perSon);
     a.start();
     d.start();

 }
}
//生产者
public class milkWork implements  Runnable {
    private  box box;

    public milkWork(box box) {
       this.box=box;
    }

    @Override
    public void run() {
        for (int a=1;a<10;a++){
            box.setMilk(a);;
        }
    }
}
//消费者
public class perSon  implements Runnable{
    private  box box;
    public perSon(box box) {
    this.box=box;
    }

    @Override
    public void run() {
       while (true){
           box.getMilk();
       }
    }
}
//工厂
public class box {
    private  int milk;
    //先定义没有奶
    private  boolean fye=false;
    public synchronized void setMilk(int milk)   {
        //有奶就去等待
        if (fye){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //把奶装入
        this.milk = milk;
        System.out.println("送奶工放置了第"+ milk+"奶中");
      //   唤醒所有
        notifyAll();
//        把奶放置完后修改为有奶
        fye=true;

    }

    public synchronized void getMilk()   {
//        如果fye=true 那么!fye就是false
        //如果没有了奶就去等待送奶
       if (!fye){
           try {
               wait();
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
       }

        System.out.println("用户拿到了了第"+milk+"奶中");
       fye=false;
       notifyAll();

    }
}



实现方式二lock锁实现

package day02;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 线程间的通信: synchronized(obj)  obj.wait()/notify()
 * 生产者和消费者的设计模式:
 *    生产者线程: 存储是否最大化,最大时,等待, 非最大时,可以生产并存储数据同时,唤醒消费者的线程
 *    消费者线程: 取出数据时,验证是否为空,为空时则等待,非空时,取出并通知或唤醒生产线程
 */

class GoodsKC {
    private Queue<Integer> queue;  // 存储数据的集合(队列, 先进先出)
    private int max_size ;
    private Lock lock;
    private Condition condition; // 锁的条件

    public GoodsKC(int max_size) {
        this.max_size = max_size;
        queue = new LinkedList<>();
        lock = new ReentrantLock();  // 重入锁类,创建线程同步锁对象
        condition = lock.newCondition();
    }

    public void push(int data) throws InterruptedException {  // 存入
        lock.lock();
        while (queue.size() == max_size){
            System.out.println(Thread.currentThread().getName() +" 当前仓库已满");
            condition.await(); // 锁条件的等待
        }
        queue.offer(data);  // 压入队列(从右侧)
        System.out.println(Thread.currentThread().getName()+" 存入"+ data +"成功");

        // 通知消费线程可以取数据
        condition.signalAll();
        lock.unlock();
    }

    public int poll() throws InterruptedException {  // 取,弹出
        lock.lock();
            while (queue.isEmpty()){
                System.out.println(Thread.currentThread().getName() +" 当前仓库已空");
                boolean await = condition.await(1, TimeUnit.SECONDS); // 如果超时,则返回false
                if(!await) {
                    lock.unlock(); // 释放锁,让其它的消费者线程进入
                    throw new InterruptedException();
                }
            }

            Integer data = queue.poll();  // 弹出, peek()获取队列最左边的元素
            System.out.println(Thread.currentThread().getName() +" 消费了"+data);
            condition.signalAll();

        lock.unlock();
        return data;
    }

}

class ProducerTask implements Runnable{
    private GoodsKC kc;
    private int start_, end_;

    public ProducerTask(GoodsKC kc, int start_, int end_) {
        this.kc = kc;
        this.start_ = start_;
        this.end_ = end_;
    }

    @Override
    public void run() {
        for (int i = start_; i <= end_; i++) {
            try {
                kc.push(i);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(Thread.currentThread().getName()+" 停止生产");
    }
}

class ConsumerTask implements Runnable{
    private GoodsKC kc;

    public ConsumerTask(GoodsKC kc) {
        this.kc = kc;
    }

    @Override
    public void run() {
        while (true){
            try {
                int data = kc.poll();
            } catch (InterruptedException e) {
                break;
            }
            try {
                Thread.sleep(400);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(Thread.currentThread().getName()+" 停止消费");
    }
}

public class TestThread1 {
    public static void main(String[] args) {
        GoodsKC goodsKC = new GoodsKC(10);
        // 生产线程
        Thread t1 = new Thread(new ProducerTask(goodsKC,1, 10));
        Thread t2 = new Thread(new ProducerTask(goodsKC,11, 20));

        // 消费者线程
        Thread t3 = new Thread(new ConsumerTask(goodsKC));
        Thread t4 = new Thread(new ConsumerTask(goodsKC));
        Thread t5 = new Thread(new ConsumerTask(goodsKC));

        for (Thread t: Arrays.asList(t1, t2, t3,t4, t5)) {
            t.start();
        }

    }
}

 2.实现方式二:synchronized关键字实现

package day01;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;

/**
 * 线程间的通信: synchronized(obj)  obj.wait()/notify()
 * 生产者和消费者的设计模式:
 *    生产者线程: 存储是否最大化,最大时,等待, 非最大时,可以生产并存储数据同时,唤醒消费者的线程
 *    消费者线程: 取出数据时,验证是否为空,为空时则等待,非空时,取出并通知或唤醒生产线程
 */

class GoodsKC {
    private Queue<Integer> queue;  // 存储数据的集合(队列, 先进先出)
    private int max_size ;
    private Object lock;   //  = new Object(); 饿汉式

    public GoodsKC(int max_size) {
        this.max_size = max_size;
        queue = new LinkedList<>();
        lock = new Object();  // 赖汉式
    }

    public void push(int data) throws InterruptedException {  // 存入
        synchronized (lock){
            while (queue.size() == max_size){
                System.out.println(Thread.currentThread().getName() +" 当前仓库已满");
                lock.wait();
            }
            queue.offer(data);  // 压入队列(从右侧)
            System.out.println(Thread.currentThread().getName()+" 存入"+ data +"成功");

            // 通知消费线程可以取数据
            lock.notifyAll();
        }
    }

    public int poll() throws InterruptedException {  // 取,弹出
        synchronized (lock){
            while (queue.isEmpty()){
                System.out.println(Thread.currentThread().getName() +" 当前仓库已空");
                lock.wait();
            }

            Integer data = queue.poll();  // 弹出, peek()获取队列最左边的元素
            System.out.println(Thread.currentThread().getName() +" 消费了"+data);
            lock.notifyAll();  // 通知生产线程,可以存数据
            return data;
        }
    }

}

class ProducerTask implements Runnable{
    private GoodsKC kc;
    private int start_, end_;

    public ProducerTask(GoodsKC kc, int start_, int end_) {
        this.kc = kc;
        this.start_ = start_;
        this.end_ = end_;
    }

    @Override
    public void run() {
        for (int i = start_; i <= end_; i++) {
            try {
                kc.push(i);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class ConsumerTask implements Runnable{
    private GoodsKC kc;

    public ConsumerTask(GoodsKC kc) {
        this.kc = kc;
    }

    @Override
    public void run() {
        while (true){
            try {
                int data = kc.poll();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            try {
                Thread.sleep(400);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class TestThread7 {
    public static void main(String[] args) {
        GoodsKC goodsKC = new GoodsKC(10);
        // 生产线程
        Thread t1 = new Thread(new ProducerTask(goodsKC,1, 20));
        Thread t2 = new Thread(new ProducerTask(goodsKC,21, 50));

        // 消费者线程
        Thread t3 = new Thread(new ConsumerTask(goodsKC));
        Thread t4 = new Thread(new ConsumerTask(goodsKC));
        Thread t5 = new Thread(new ConsumerTask(goodsKC));

        for (Thread t: Arrays.asList(t1, t2, t3,t4, t5)) {
            t.start();
        }

    }
}

Lock接口

说明:说明:JDK1.5提供的同步锁操作接口

Condition newCondition() 获取锁的情况,便于操作线程的状态

使用 Condition condition = lock.newCondition();

1) lock() 获取锁   如锁被占用,则等待。

2)boolean tryLock()  尝试获取锁  成功返回true,失败返回false,不阻塞

Conditon接口

1)await() 等待

2)signal() 唤醒

3)signalAll() 唤醒所有

ReentrantLock类

使用 Lock lock = new ReentrantLock();

扩展-同步的集合类

1.Collections工具类

1)public static <T> Collection<T> synchronizedCollection(Collection<T> c)

2)public static <T> List<T> synchronizedList(List<T> list)

3)public static <T> Set<T> synchronizedSet(Set<T> s)

4)public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m)

5)public static <T> SortedSet<T> synchronizedSortedSet(SortedSet<T> s)

6)public static <K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m)

说明:JDK1.2提供,接口统一、维护性高,但性能没有提升,均以synchonized实现。

2.3.CopyOnWriteArrayList

1)线程安全的ArrayList,加强版读写分离

2)写有锁,读无锁,读写之间不阻塞,优于读写锁。

3)写入时,先copy一个容器副本、再添加新元素,最后替换引用

4)使用方式与ArrayList无异

3.CopyOnWriteArraySet

1)线程安全的Set,底层使CopyOnWriteArrayList实现

2)唯一不同在于,使用addIfAbsent()添加元素,会遍历数组

3)如存在元素,则不添加(扔掉副本)

4.ConcurrentHashMap

1)初始容量默认为16段(Segment),使用分段锁设计

2) 不对整个Map加锁,而是为每个Segment加锁。

3)最理想状态为16个对象分别存入16个Segment,并行数量16。

4)当多个对象存入同一个Segment时,才需要互斥。

5)使用方式与HashMap无异。

6)JDK1.8改为CAS无锁算法

5.ConcurrentLinkedQueue

1)线程安全、可高效读写的队列,高并发下性能最好的队列

2)无锁、CAS比较交换算法,修改的方法包含三个核心参数(V,E,N)

     V:要更新的变量、E:预期值、N:新值。

    只有当V==E时,V=N;否则表示已被更新过,则取消当前操作

3)核心方法  offer(v)  插入    poll() 删除    peek() 获取

6.BlockingQueue接口

1)void put(E e) //将指定元素插入此队列中,如果没有可用空间,则等待

2)E take() //获取并移除此队列头部元素,如果没有可用元素,则等待

3)可用于解决生产生、消费者问题

4)实现类

ArrayBlockingQueue   数组结构实现,有界队列(手工固定上限)

LinkedBlockingQueue   链表结构实现,无界队列。(默认上限Integer.MAX_VALUE)

例子

package day02;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

  class TestBlockingQueue {
    public static void main(String[] args) {
        // 将普通的List转化为线程安全的List
        final BlockingQueue<String> data = new ArrayBlockingQueue<String>(10);

        // 创建三个线程产出数据
        Runnable task1 = new Runnable() {
            @Override
            public void run() {
                String item = UUID.randomUUID().toString();
                System.out.println(Thread.currentThread().getName()+"产出"+item);
                data.add(item);

            }
        };
        ExecutorService service1 = Executors.newFixedThreadPool(3);
        service1.submit(task1);
        service1.submit(task1);
        service1.submit(task1);
        service1.shutdown();
        // 创建两个线程 删除数据
        Runnable task2 = new Runnable() {
            @Override
            public void run() {
                try {
                    String item = data.take(); // 阻塞
                    System.out.println(Thread.currentThread().getName()+" 消费了"+item);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        ExecutorService service2 = Executors.newFixedThreadPool(2);
        service2.execute(task2);
        service2.execute(task2);
        service2.shutdown();
    }
}

方法

释义

Thread.currentThread().getName()

获取当前线程的名字

Thread.yield();

尽可能让出cpu的执行权

wait();

等待

notifyAll();

唤醒

thread.join();

插队线程,我先执行,其他人往后

thread.setPriority(1);

设置线程优先级为1-10

thread.setDaemon(true);

设置守护线程,守护其他线程执行完后自己慢慢关闭

executorService.submit(myThread);

线程池提交任务

executorService.shutdown();

关闭线程池

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值