多线程基础和synchronized的使用

##多线程
线程是系统中最小的执行单元,同一个进程有多个线程,线程共享进程的资源。

####线程间的交互
1.同步:wait()/notify()/notifyAll(),锁对象通过前面几个方法,通知在等待的线程可以开始竞争CPU资源了。

2.互斥:同一个数据对象只能被一条线程使用,其他线程要等待这个线程使用完才能通过竞争使用当前数据对象。

###Runnable和Thread的区别:
Runnable方式可以避免Thread方式由于Java单继承特性带来的缺陷。

Runnable的代码可以被多个线程(Thread实例)共享,适合于多个线程处理统一资源的情况。

###线程的生命周期:
1.创建:调用new创意见Thread对象时。

2.就绪:调用start()后,此时线程只是进入了线程队列,等待获取CPU服务,具备了运行条件,但并不一定已经开始运行了。

3.运行:处于就绪的线程,一旦获取了CPU资源,便进入了运行状态,开始执行run方法里面的逻辑。

4.终止:线程的run方法执行完毕,或者线程调用了stop方法(这个方法已经被淘汰了),线程便进入终止状态。

5.阻塞:一个正在执行的线程在某些情况下,由于某种原因而暂时让出了CPU资源,暂停了自己的执行,便进入了阻塞状态,如调用了sleep()方法。

###线程的分类:
用户线程:运行在前台,执行具体的任务。(程序的主线程、连接网络的子线程等都是用户线程)。

守护线程:运行在后台,为其他前台线程服务。

特点:一旦所有用户线程都结束运行,守护线程会随JVM一起结束工作。

应用:数据库连接池中的检测线程。

###设置守护线程
可以通过调用Thread的setDaemon(true)方法来设置当前的线程为守护线程。

注意事项:

  • setDaemon(true)必须在start()方法之前调用,否则会抛出IllegalThreadStateException异常。
  • 在守护线程中产生的新线程也是守护线程。
  • 不是所有的任务都可以分配给守护线程来执行,比如读写操作或者计算逻辑。

###synchronize
作用:能够保证在同一时刻最多只有一个线程执行该段代码,已达到保证并发安全的效果。

地位:1.是最基本的互斥同步手段。 2.是并发编程中的元老级角色,是并发编程的必学内容。

###synchronized的性质:
1.可重入:指的是同一线程的外层函数获得锁之后,内层函数可以直接再次获取该锁。

  • 好处:避免死锁、提升封装性。
  • 粒度:线程而非调用。(用三种情况来说明和pthread的区别)

情况1:证明同一个方法是可重入的。

情况2:证明可重入不要求是同一个方法。

情况3:证明可重入不要求是同一个类中的。

2.不可中断:
一旦这个锁已经被别人获得了,如果我还想获得,我只能选择等待或者阻塞,知道别的线程释放这个锁。如果别人永远不释放锁,那么我只能永远等下去。

相比之下,Lock类拥有可以中断的能力,第一点,如果我觉得我等待的时间太长了,有权中断现在已经获取到的线程的执行;第二点,如果我觉得我等待的时间太长了不想再等了,也可以退出。

###synchronized可见性原理:
被synchronized修饰的方法或者代码块,在方法或者代码块执行完了后,本地内存修改的内容都会由JVM回写到主内存中,在调用方法或使用代码块获取数据时,也是先从主内从中读取对象数据。这样保证了数据的同一性,完成了线程间的通信。

###synchronized的缺陷
1.效率低:锁的释放情况少、试图获得锁时不能设定超时、不能中断一个正在试图获得锁的线程。

2.不够灵活(读写锁更灵活):加锁和释放的时机单一,每个锁仅有单一的条件(某个对象),可能是不够的。

3.无法知道是否成功获取到锁。

###多线程访问同步方法的7种具体情况:
1.两个线程同时访问一个对象的同步方法。

public class First implements Runnable {
  static int count = 0;

  @Override
  public void run() {
    synchronized (this) {
        for (int i = 0; i < 10000; i++) {
            count++;
        }
    }
 }

public static void main(String[] args) {
    try {
        String name = Thread.currentThread().getName();
        System.out.println(name + "开始计数!");

        First first = new First();
        Thread thread1 = new Thread(first);
        Thread thread2 = new Thread(first);
        thread1.start();
        thread2.start();
 //为了线程执行完,再答应计算结果。
//        thread1.join();
//        thread2.join();
        while (thread1.isAlive() || thread2.isAlive()){}
        System.out.println(name + "计算的结果:" + count);
    } catch (Exception e) {
        e.printStackTrace();
    }
 }
}

2.两个线程访问两个对象的同步方法。

public class Two implements Runnable {
  static int count = 0;

  @Override
  public void run() {
    synchronized (this) {
        for (int i = 0; i < 10000; i++) {
            count++;
        }
    }
  }

  public static void main(String[] args) throws InterruptedException {
    String name = Thread.currentThread().getName();
    System.out.println(name + "开始两个线程访问两个对象的同步方法!");
    Two two1 = new Two();
    Two two2 = new Two();
    Thread thread1 = new Thread(two1);
    Thread thread2 = new Thread(two2);
    thread1.start();
    thread2.start();
    thread1.join();
    thread2.join();
    System.out.println(name + "计数结果:"+ count);

  }
}

3.两个线程访问的是synchronized的static方法。

public class Three implements Runnable {
  @Override
  public void run() {
    method();
  }

  //锁是类锁
  private synchronized static void method() {
    String name = java.lang.Thread.currentThread().getName();
    System.out.println(name + "执行两个线程访问的是synchronize的static方法");
    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println(name + "执行完了两个线程访问的是synchronize的static方法");
  }

  public static void main(String[] args) {
    Three three1 = new Three();
    Three three2 = new Three();
    Thread thread1 = new Thread(three1);
    Thread thread2 = new Thread(three2);
    thread1.start();
    thread2.start();
    while (thread1.isAlive() || thread2.isAlive()){
    }

    System.out.println("结束了任务!");

  }
}

4.同时访问同步方法与非同步方法。

public class Four implements Runnable {
  @Override
  public void run() {
    String name = Thread.currentThread().getName();
    if ("Thread-0".equals(name)){
        method1();
    }else {
        method2();
    }
  }

 private synchronized void method1() {
    String name = java.lang.Thread.currentThread().getName();
    System.out.println(name + "执行了线程的synchronize的方法");
    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    System.out.println(name + "执行完了线程的synchronize的方法");
  }

  private void method2() {
    String name = java.lang.Thread.currentThread().getName();
    System.out.println(name + "执行了线程的非synchronize的方法");
    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    System.out.println(name + "执行完了线程的非synchronize的方法");
  }

  public static void main(String[] args){
    Four four = new Four();
    Thread thread1 = new Thread(four);
    Thread thread2 = new Thread(four);

    thread1.start();
    thread2.start();
    try {
        thread1.join();
        thread2.join();
    }catch (Exception e){
        e.printStackTrace();
    }

    while (thread1.isAlive() || thread2.isAlive()){}

    System.out.println("执行完了任务");

  }
}

5.访问同一个对象的不同的普通同步方法。

public class Five implements Runnable {
  @Override
  public void run() {
    String name = Thread.currentThread().getName();
    if (name.equals("Thread-0")){
        method1();
    }else {
        method2();
    }
  }

  private synchronized void method1() {
    String name = Thread.currentThread().getName();
    System.out.println(name + "执行了method1");
    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    System.out.println("method1执行完了");

  }

  private synchronized void method2() {
    String name = Thread.currentThread().getName();
    System.out.println(name + "执行了method2");
    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    System.out.println("method2执行完了");
  }

  public static void main(String[] args){
    Five five = new Five();

    Thread thread1 = new Thread(five);
    Thread thread2 = new Thread(five);

    thread1.start();
    thread2.start();

    while (thread1.isAlive() || thread2.isAlive()){}

    System.out.println("执行完了任务!");

  }
}

6.同时访问static的synchronized和非static的synchronized方法。

public class Sex implements Runnable {
  @Override
  public void run() {
    String name = Thread.currentThread().getName();
    if (name.equals("Thread-0")){
        method1();
    }else {
        method2();
    }
}

private synchronized void method1() {
    String name = Thread.currentThread().getName();
    System.out.println(name + "执行了method1");
    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    System.out.println(name + "的method1执行完了");

}

private static synchronized void method2() {
    String name = Thread.currentThread().getName();
    System.out.println(name + "执行了method2");
    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    System.out.println(name +"的method2执行完了");
}

public static void main(String[] args){
    Sex sex = new Sex();
    Thread thread1 = new Thread(sex);
    Thread thread2 = new Thread(sex);

    thread1.start();
    thread2.start();

    while (thread1.isAlive() || thread1.isAlive()){}

    System.out.println("任务执行完了!");


  }
}

7.方法抛出异常后,会释放锁。
public class Seven implements Runnable {
@Override
public void run() {
String name = Thread.currentThread().getName();
if (name.equals(“Thread-0”)){
method1();
}else {
method2();
}
}

private synchronized void method1() {
    String name = Thread.currentThread().getName();
    System.out.println(name + "执行了method1");
    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    throw new RuntimeException();

// System.out.println(name + "的method1执行完了");

}

private synchronized void method2() {
    String name = Thread.currentThread().getName();
    System.out.println(name + "执行了method2");
    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    System.out.println(name +"的method2执行完了");
}

public static void main(String[] args){
    Sex sex = new Sex();
    Thread thread1 = new Thread(sex);
    Thread thread2 = new Thread(sex);

    thread1.start();
    thread2.start();

    while (thread1.isAlive() || thread1.isAlive()){}

    System.out.println("任务执行完了!");


  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值