一、摘要
每天都和电脑打交道,也相信大家使用过资源管理器杀掉过进程。而windows本身就是多进程的操作系统
在这里我们理解两组基本概念:
1、进程和线程的区别????
2、并行与并发的区别????
那么针对进程与线程而言:
什么是进程:进程其实就是一个运行的程序,操作系统会为这个进行资源分配从而执行程序
什么是线程:线程是程序的一个执行线索,即是进程的一个执行流程,一个进程内部可以开辟多个线程
对并行与并发而言:
什么是并行:并行指的是多个cpu同时去处理一段逻辑
什么是并发:并发指的个线程在抢夺cpu时间片,谁先抢到谁就执行,从而更加高效的利用资源
二:多线程创建的三种方式
1、继承Thread类
2、实现Runnable接口
3、通过线程池进行线程的创建,后续章节会讲到
三、线程创建方式一:继承Thread类
这种方式创建线程缺点如下:
1、每次都创建新的线程对象具有各自的变量,无法共享数据
2、java只支持单继承,碰到线程类有一个父类的时候,则无法继承Thread类
public class Demo1 { public static void main(String[] args) { MyThread myThread=new MyThread(); myThread.start(); System.out.println("继承Thread类"); } } class MyThread extends Thread { public void run() { System.out.println("创建的线程"); } }
四、线程创建方式二:实现Runnable接口
使用该方式创建线程时:
1、可以实现成员变量的共享
2、可以实现多接口,不存在继承问题
public class MyRunnable implements Runnable { @Override public void run() { System.out.println("运行中!"); } } public class Demo2{ public static void main(String[] args) { Runnable runnable=new MyRunnable(); Thread thread=new Thread(runnable); thread.start(); System.out.println("运行结束!"); } }
五、多线程并发安全问题
1、所谓多线程并发安全指的是多个线程在去并发操作共享的资源时,操作过程中包含多个步骤,由于线程的并发则会造成执行混乱的一些问题
2、解决办法一:使用同步代码块隔离多线程
/** * Created by BeiChen on 2018/3/18. */ public class ThreadDemo1 { public static void main(String[] args) { MyThread mt=new MyThread(); Thread t1=new Thread(mt); Thread t2=new Thread(mt); t1.start(); t2.start(); } } class MyThread implements Runnable{ int num=100; @Override public void run() { while (true){ synchronized (this){ if(num>0){ System.out.println(Thread.currentThread().getName()+"执行了,此时num值为"+num); }else{ break; } num--; } } } }
从上述代码中我们可以得出:
1)、同步代码块要将造成多线程并发安全问题的代码都要括上,一般来说多线程并发安全问题都是由于同时读取和修改共同执行造成的问题,在使用同步代码块时,将读和改的操作都要括起来。
2)、同步代码块可以解决多线程并发安全问题,但是在同步代码块中相当于将多线程变成了单线程,程序的性能会降低,所以同步代码块中的代码不能太多,应该在保证能够防止多线程并发安全问题的前提下代码尽量少,从而减少程序代码对性能的影响
3)、任何对象都可以当做锁对象来使用,但是必须保证这个对象是所有要用这个锁的并发线程都能看到的同一个对象才可以。多个线程用同一个锁对象,在它身上控制锁的开光,控制程序的并发
常见的锁对象:共享资源对象,this ,类的class字节码对象
3、解决办法二:使用同步函数来解决
上述代码也可以改写成:
public class ThreadDemo1 { public static void main(String[] args) { MyThread mt=new MyThread(); Thread t1=new Thread(mt); Thread t2=new Thread(mt); t1.start(); t2.start(); } } class MyThread implements Runnable{ int num=0; @Override public void run() { for(int i=0;i<100;i++){ add(i); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } public synchronized void add(int i) { System.out.println(Thread.currentThread().getName() + "执行了,此时i值为" + i); } }
在上述使用同步函数处理并发安全问题时,我们可以看出同步可以将这个方法设置为同步方法,这个方法本身自动就会用锁隔离
同时同步函数默认使用的锁对象是this
如果同步函数是静态方法,没有this对象,此时使用的锁对象是当前的额字节码对象
六、死锁问题
死锁问题指的是两个线程资源在互相的等待导致了死锁,死锁问题一旦产生就是很严重的问题
代码案例如下:
/** * Created by BeiChen on 2018/3/18. */ public class DeadLockDemo { public static void main(String[] args) { new Thread(new Lock1()).start(); new Thread(new Lock2()).start(); } } class Demo1{} class Demo2{} class Lock1 implements Runnable{ @Override public void run() { System.out.println("lock1 开始运行"); synchronized (Demo1.class){ System.out.println("Lock1 锁住了 Demo1"); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (Demo2.class){ System.out.println("Lock1 锁住了Demo2"); } } } } class Lock2 implements Runnable{ @Override public void run() { System.out.println("lock2 开始运行"); synchronized (Demo2.class){ System.out.println("Lock2 锁住了 Demo2"); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (Demo1.class){ System.out.println("Lock2 锁住了Demo1"); } } } }
在上述我们可以看出Lock1和Lock2相互锁住了自己的对象导致死锁的问题产生
最简单的解决办法如下:
将同步嵌套的代码放开,不要进行同步嵌套,同步嵌套是造成死锁的必然原因,想要防止死锁,只要保证没有同步嵌套就可以了
代码改造如下:
/** * Created by BeiChen on 2018/3/18. */ public class DeadLockDemo { public static void main(String[] args) { new Thread(new Lock1()).start(); new Thread(new Lock2()).start(); } } class Demo1{} class Demo2{} class Lock1 implements Runnable{ @Override public void run() { System.out.println("lock1 开始运行"); synchronized (Demo1.class) { System.out.println("Lock1 锁住了 Demo1"); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } synchronized (Demo2.class){ System.out.println("Lock1 锁住了Demo2"); } } } class Lock2 implements Runnable{ @Override public void run() { System.out.println("lock2 开始运行"); synchronized (Demo2.class) { System.out.println("Lock2 锁住了 Demo2"); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } synchronized (Demo1.class){ System.out.println("Lock2 锁住了Demo1"); } } }