多线程(一)
October 6, 2016 9:13 PM Power By DeiMo
多线程概述
1.进程与线程
- 进程:正在运行中的程序
- 线程:进程中负责程序执行的控制单元(执行路径)一个进程可以有多个执行路径,称之为多线程
2.多线程的意义
开启多个线程是为了同时运行多部分代码,每一个线程都有自己运行的内容。这个内容就是多线程要执行的任务
3.多线程的好处与弊端
- 好处:解决了多部分程序同时运行的问题。
- 弊端:线程太多反而会导致CPU处理效率的降低,这是因为应用程序的执行都是CPU在做着快速的切换完成的,而这个切换是随机的。(请参考CPU工作原理)
创建多线程的两种方式
1.继承Thread类并重写run()方法
使用步骤
1)继承Thread类
2)重写run()方法
3)构造Thread对象
4)调用start()方法,开启线程
class Demo extends Thread {
private String name;
public Demo(String name) {
super(name);
this.name = name;
}
@Override
public void run() {
show();
}
private void show() {
for (int i = 0; i < 10; i++) {
System.out.println(name + "...." + i+"...."+Thread.currentThread().getName());
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
Demo d1 = new Demo("hahah");
Demo d2 = new Demo("xixixixi");
d1.start();
d2.start();
System.out.println("------------------------------------------------"+Thread.currentThread().getName());
}
}
2.实现Runnable接口(封装线程任务)
使用步骤
1)实现Runnable接口
2)重写run()方法
3)构造Thread对象
4)调用start()方法,开启线程
class Ticket implements Runnable {
private int num = 100;
@Override
public void run() {
while (true) {
if (num > 0) {
System.out.println(Thread.currentThread() + "....." + num--);
}
}
}
}
public class ThreadTest {
public static void main(String[] args) {
Ticket t = new Ticket();
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
t1.start();
t2.start();
}
}
不难发现使用第二种方式有如下好处
1.将线程的任务从子类中分离出来,进行了单独的封装。按照面向对象的思想将任务封装成对象,提供更大的灵活性
2.避免了单继承的局限性
多线程运行图解
多线程的运行状态
线程安全
问题的产生
当一个线程在执行操作共享数据的多条代码中,其它线程若参与了运算,就会导致线程安全问题的产生。
产生原因:
- 1.多个线程在操作共享数据
- 2.操作数据的代码有多条
解决方案
解决思路
将多条操作共享数据的代码封装起来,当有线程在执行这些代码时候,其他线程不可以参与运算。简单说来:就是必须要当前代码都执行完毕后,其他线程才可以参与运算。
具体方法
针对上述思路,java提供了一种称为“同步(synchronized)”解决方案,它有两种表现形式
同步代码块
//同步代码块的格式 synchronized(Object obj){//这里的obj称为:”锁“对象,理论上可以为任意类型 //要同步的代码块 }
同步函数(同步代码块的简写形式,在修饰符后,返回值前使用关键字 synchronized )
class Ticket implements Runnable { private int num = 100; private Object obj = new Object(); boolean flag = true; @Override public void run() { System.out.println("this:"+this); if (flag) { while (true) { synchronized (obj) { if (num > 0) { try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread() + ".....obj...." + num--); } } } } else { while (true) { show(); } } } private synchronized void show() { if (num > 0) { try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread() + "...this..." + num--); } } } public class SynFunctionLockDemo { public static void main(String[] args) { Ticket t = new Ticket(); System.out.println("t:"+t); Thread t1 = new Thread(t); Thread t2 = new Thread(t); t1.start(); try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } t.flag = false; t2.start(); } }
同步的相关说明
- 好处
解决了线程的安全问题
- 弊端
相对降低了效率,因为同步的线程都会去判断同步锁- 使用前提
同步中必须有多个线程并使用同一个锁
同步中的锁
锁的概念
一段synchronized的代码被一个线程执行之前,他要先拿到执行这段代码的权限,在Java里边就是拿到某个同步对象的锁(一个对象只有一把锁); 如果这个时候同步对象的锁被其他线程拿走了,他(这个线程)就只能等了(线程阻塞在锁池等待队列中)。 取到锁后,他就开始执行同步代码(被synchronized修饰的代码);线程执行完同步代码后马上就把锁还给同步对象,其他在锁池中等待的某个线程就可以拿到锁执行同步代码了。这样就保证了同步代码在统一时刻只有一个线程在执行。
同步函数的锁
非静态同步函数的锁是 this
静态同步函数的锁是 同步所在类Class对象,可由this.getclass()方法或者类.class属性获取
死锁
由于死锁深入研究起来比较复杂,此处仅简要说明,并附上一个java死锁的示例
死锁的概念
死锁是进程死锁的简称,是由Dijkstra于1965年研究银行家算法时首先提出来的。它是计算机操作系统乃至并发程序设计中最难处理的问题之一。实际上,死锁问题不仅在计算机系统中存在,在我们日常生活中它也广泛存在。所谓死锁,是指多个进程循环等待它方占有的资源而无限期地僵持下去的局面。很显然,如果没有外力的作用,那麽死锁涉及到的各个进程都将永远处于封锁状态。
示例代码
class Test implements Runnable {
protected boolean flag;
public Test(boolean flag) {
super();
this.flag = flag;
}
@Override
public void run() {
if (flag) {
synchronized (Mylock.loacA) {
System.out.println("if................lockA");
synchronized (Mylock.lockB) {
System.out.println("if..................loackB");
}
}
} else {
synchronized (Mylock.lockB) {
System.out.println("else..................loackB");
synchronized (Mylock.loacA) {
System.out.println("else..................loackA");
}
}
}
}
}
class Mylock {
public static final Mylock loacA = new Mylock();
public static final Mylock lockB = new Mylock();
}
public class DeadLockTest {
public static void main(String[] args) {
Test test1 = new Test(true);
Test test2 = new Test(false);
Thread t1 = new Thread(test1);
Thread t2 = new Thread(test2);
t1.start();
t2.start();
}
}