Java多线程

创建线程

1.继承Thread

public class Main {

    public static void main(String[] args) throws ParseException {
        MyThread t=new MyThread();
        t.start();
    }
}
class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+":hello");
    }
}

2.实现Runnable接口

public class Main {

    public static void main(String[] args) throws ParseException {
      Thread t=new Thread(new MyThread());
      t.start();
    }
}
class MyThread implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+":hello");
    }
}

3.线程池
Executor:线程池顶级接口
ExecutorService:线程池接口,可通过submit(Runnable task)提交任务代码
Executors工厂类:通过此类可以获得一个线程池
方法:
newFixedThreadPool(int nThreads)获取固定数量的线程池
newCachedThreadPool()获得动态数量的线程池

public class Main {

    public static void main(String[] args) throws ParseException {
    ExecutorService es=Executors.newFixedThreadPool(2);
    es.submit(MyThread.getMyThread());
    es.submit(MyThread.getMyThread());
    es.shutdown();
    }
}


class MyThread implements Runnable{
    public static int res=0;
    public static int index=1;
   public static MyThread m=new MyThread();
private MyThread(){ }
public static MyThread getMyThread(){
    return m;
}
    Lock lock=new ReentrantLock();
    @Override
    public  void run() {

      while(index<=10000){
          try {
              lock.lock();
             if(index>10000){
                 break;
             }
              res += index;
              index++;
              System.out.println(Thread.currentThread().getName() + " " + res);
          }finally {
              lock.unlock();
          }
          }
        }
}

Callable接口
JDK1.5加入,与Runnable接口相似,实现之后代表一个线程任务
Callable具有泛型返回值,可以声明异常
public interface Callable{
public V call() throws Exception;
}

返回值通过Future接口接收
get()阻塞形式等待Future中的异步处理结果(call()的返回值)


    public static void main(String[] args) throws ParseException {
    ExecutorService es=Executors.newFixedThreadPool(2);
    //用Future接收
    Future<String> future=es.submit(new MyCallable());
        try {
            //future.get()方法得到返回值
            System.out.println(future.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        es.shutdown();
    }
}
class MyCallable implements Callable<String>{

    @Override
    public String call() throws Exception {
        return "hello";
    }
}

Thread类常见方法

Thread.sleep(毫秒)
让当前进程进入休眠,让出CPU使用权,直到休眠结束才会继续抢占CPU 不会释放锁
Thread.yield()
线程礼让 让出CPU使用权 但是会马上又去抢占CPU,进入就绪态,不会释放锁
join()
在当前线程中加入另一线程,必须将另一线程执行完后才会继续执行当前线程

加锁方式

Synchronized

可以加在代码块和方法上

方式一:同步代码块

  • synchronized(临界资源对象){ //互斥锁标记
  • ​ //原子代码
  • }

方式二:同步方法

  • public synchronized void sale(){ //互斥锁标记是this对象
  • ​ //原子代码
  • }

Lock

class MyThread implements Runnable{
    public static int res=0;
    public static int index=1;
   public static MyThread m=new MyThread();
private MyThread(){ }
public static MyThread getMyThread(){
    return m;
}
    Lock lock=new ReentrantLock();
    @Override
    public  void run() {

      while(index<=10000){
          try {
              lock.lock();
             if(index>10000){
                 break;
             }
              res += index;
              index++;
              System.out.println(Thread.currentThread().getName() + " " + res);
          }finally {
              lock.unlock();
          }
          }
        }
}

lock锁一定要采用以下形式:

Lock l = …;
l.lock();
try {
// access the resource protected by this lock
} finally {
l.unlock();
}

不然如果前面代码出现异常执行不下去导致没有unlock 会导致死锁(unlock必须执行)

读写锁

ReetrantReadWriteLock:

1.创建读写锁对象:ReadWriteLock rwl = new ReentrantReadWriteLock();
2.创建读锁 :Lock readLock = rwl.readLock();
3.创建写锁:Lock writeLock = rwl.writeLock();

class RandW{
    private static RandW rw=new RandW();
    ReadWriteLock rwlock=new ReentrantReadWriteLock();
    Lock readlock=rwlock.readLock();
    Lock writelock=rwlock.writeLock();
    private RandW(){}
    public static RandW getRandW(){
        return rw;
    }
    String msg;
    public void setMsg(String msg){
        try{
            writelock.lock();
            this.msg=msg;
        }finally {
            writelock.unlock();
        }
    }
    public void getMsg(){
        try {
            readlock.lock();
            System.out.println(msg);
        }finally {
            readlock.unlock();
        }
        }
}
class MyThread3 implements Runnable{

    @Override
    public void run() {
        RandW rw=RandW.getRandW();

        rw.setMsg("hello");
    }
}
class MyThread4 implements Runnable{

    @Override
    public void run() {
         RandW rw=RandW.getRandW();
         rw.getMsg();
    }
}

MyThread3读 MyThread4写

重入锁

重入锁:

  • 重入锁也叫作递归锁,指的是同一个线程外层函数获取到一把锁后,内层函数同样具有这把锁的控制权限

  • synchronized和Lock锁都可以实现锁的重入

公平锁

公平锁和非公平锁

  • 非公平锁:优先使用上一个线程接着执行下面的线程任务
    • synchronized是非公平锁的实现,无法实现公平锁
    • lock锁默认是非公平锁,如果想要实现公平锁,那么需要在构造方法设置为true
  • 公平锁:让每个线程都公平去执行线程任务
    • lock锁可以实现公平锁
    • synchronized无法实现公平锁
//Lock锁实现公平锁 参数为true表示是公平锁,默认是false表示非公平锁
Lock lock = new ReentrantLock(true);

synchronized锁升级

锁的状态总共有四种

  • 无锁
    • 当锁对象被创建,还没有线程进入的是,此时锁对象处于无锁状态
  • 偏向锁
    • 当有线程A进入同步代码并获得锁对象,此时会保存线程ID。以后此线程A进入到同步代码中则无需使用CAS加锁或者释放锁。只需要验证线程ID即可。
  • 轻量级锁(自旋锁)
    • 当前锁处于偏向锁,此时后线程B进入到同步代码。这是线程AB会使用CAS竞争,并升级为轻量级锁
  • 重量级锁
    • 如果线程没有获得轻量级锁,线程会通过CAS自旋获取锁对象,如果自旋次数大于阈值(10次),则升级为重量级锁。
      在这里插入图片描述

线程安全的集合

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值