1.线程同步

  2.线程通信

  3.线程池

  4.生产者消费者模型(以馒头为例)

 

一、线程同步

  由来:多个线程同时访问一个对象,需要对这个对象进行协调

  同步 synchronized
  可以修饰方法 同步方法
  可以修饰对象 同步对象

 如果不使用线程锁会出现以下情况:

  Java学习--线程(二)

 

两次id的结果相加不等于原始id

  同步锁,一个时间点上只允许一个线程操作一个方法或对象
  一个线程访问同步代码块,其他非同步的代码还是可以被多个线程同时访问
  当前线程访问同步代码块时,就获得了锁,访问完毕后会释放锁。

使用同步锁后会出现如下情况:

 Java学习--线程(二)

以下是使用synchronized关键字的基本实现代码:

package com.demo.thread;

public class Demo {
    public static void main(String[] args) {
        Entity e = new Entity();
        e.setId(1000);
        Thread t = new Thread(new IdThread(e,300),"t");
        Thread t1 = new Thread(new IdThread(e, 300),"t1");
        t1.start();
        t.start();
    }
}
/**
 * Id实体类
 * @author Administrator
 *
 */
class Entity{
    private int id;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    /**
     * 减少id
     */
    public void reduceId(int count){
        id = id - count;
    }
}
/**
 * Id线程类
 * @author Administrator
 *
 */
class IdThread implements Runnable {
    private Entity e ;
    private int count;
    /**
     * 通过构造传参的方法获取同一个entity对象
     * @param e
     * @param count
     */
    public IdThread(Entity e,int count) {
        this.e=e;
        this.count = count;
    }
    public void run() {
        int reduce = reduce();
        System.out.println(Thread.currentThread().getName()+":"+reduce);
    }
    private int reduce(){
        synchronized (e) {
            e.reduceId(count);
            return e.getId();
        }
    }
}

运行结果为:Java学习--线程(二)

如果不加锁,运行结果则会出现如下情况:Java学习--线程(二)Java学习--线程(二)

 

二、线程通信

   由于一个进程中的线程是公用的同一个资源,所以线程之间可以共享进程的内存、数据。线程通信则是对共享数据的有效操作

线程通信所用到的方法是object 类里的:

1.wait()          等待,线程处在阻塞状态

2.notify()        唤醒,通知其他另一个线程进入就绪状态

ps:使用wait()方法与notify方法时,所访问的资源必须是有synchronized字段修饰的不然会抛出一个InterruptedException

Java学习--线程(二)

package com.demo.thread;
/**
 * 线程通信主函数
 * @author Administrator
 *
 */
public class SignalDemo {
    public static void main(String[] args) {
        myObject obj = new myObject();
        obj.setSize(1200);
        new Thread(new SignalThread1(obj),"通信一").start();
        new Thread(new SignalThread2(obj),"通信二").start();
    }
}
class SignalThread1 implements Runnable{
    private myObject obj = null;
    /**
     * 构造函数里需要传入同一个对象
     * @param obj
     */
    public SignalThread1(myObject obj) {
        this.obj = obj;
    }
    @Override
    public void run() {
        //使用线程需要将对象同步
        synchronized (obj) {
            for(int i =0 ; i<10;i++){
                //由于访问的obj对象是被锁住的(同步),所有不用调用wait方法了如果额外调用则会抛出 InterruptedException
                    obj.reSize(100);
                    System.out.println(Thread.currentThread().getName()+" : "+obj.getSize());
                    if(i==3){
                        try { 
                            //线程等待
                            obj.wait();
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
            }
        }
        
        
    }
    
}
/**
 * 构造函数里需要传入同一个对象
 * @author Administrator
 *
 */
class SignalThread2 implements Runnable{
    private myObject obj = null;
    public SignalThread2(myObject obj) {
        this.obj = obj;
    }
    @Override
    public void run() {
        //使用线程需要将对象同步
        synchronized (obj) {
        for(int i =0;i<10;i++){
                obj.reSize(20);
                System.out.println(Thread.currentThread().getName()+" : "+obj.getSize());
                if(i==5){
                    obj.notify();
                }
        }
        }
    }
}
/**
 * 自定义对象
 * @author Administrator
 *
 */
class myObject{
    private int size;

    /**
     * 减少size
     */
    public void reSize(int count){
        size = size - count;
    }
    public int getSize() {
        return size;
    }

    public void setSize(int size) {
        this.size = size;
    }
    
}

 三、线程池

在某些特定的条件下,由于需要重复使用线程,如果采用传统使用线程的方法,程序的效率可能会比单线程还低。

此时需要创建一个可以重复使用的线程----线程池

创建线程池的方式

  Executors 创建线程池的工具类
  ExecutorService 线程池

方式一:创建可缓存的线程池

Java学习--线程(二)

 

方式二:创建固定个数的线程池

 Java学习--线程(二)

 

方式三:创建单个线程的线程池

 Java学习--线程(二)

 

方式四:创建定时任务的线程池

 Java学习--线程(二)

 

scheduledThreadPool.scheduleWithFixedDelay(worker, 5, 3, TimeUnit.SECONDS);

 四、生产者消费者模型(以馒头为例)

Java学习--线程(二)

 

以下为一个简单的生产者消费者模型的基本实现:

  

package demo;
/**
 * 馒头类
 * @author Administrator
 *
 */
public class Buns {
    private int id;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}
馒头类

相关文章:

  • 2021-03-30
  • 2021-07-04
  • 2022-02-06
  • 2021-11-23
  • 2021-08-13
猜你喜欢
  • 2022-02-07
  • 2021-09-29
  • 2021-10-14
  • 2022-12-23
  • 2021-11-08
  • 2022-02-21
  • 2021-10-04
相关资源
相似解决方案