Java多线程理解
一、理论概念
进程与线程
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位。
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.
进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。
二、线程的Java实现
目前实现java线程有2种方式,继承Thread类和实现Runnable接口,重写run方法。
1、实现Runnable接口
实现 Runnable的接口的好处是实现变量的共享,多个线程使用同一个Runable对象,如上代码块中的成员变量j:
package src; /** * * @author Shawn Wang * */ public class MyThread implements Runnable { private int j = 100; @Override public void run() { while (true) { if (j > 0) { System.out.println(Thread.currentThread().getName() + "-- num:" + j--); } else { break; } } } public static void main(String[] args) { MyThread mt = new MyThread(); Thread thread1 = new Thread(mt); Thread thread2 = new Thread(mt); Thread thread3 = new Thread(mt); thread1.start(); thread2.start(); thread3.start(); } }
输出结果:
Thread-1-- num:100 Thread-3-- num:98 Thread-2-- num:99 Thread-2-- num:95 Thread-3-- num:96 Thread-1-- num:97 Thread-1-- num:92 Thread-1-- num:91 Thread-3-- num:93 Thread-3-- num:89 Thread-3-- num:88 Thread-2-- num:94 Thread-2-- num:86 Thread-2-- num:85 Thread-2-- num:84 Thread-3-- num:87 Thread-3-- num:82 Thread-1-- num:90 Thread-1-- num:80 Thread-3-- num:81 Thread-3-- num:78 Thread-3-- num:77 Thread-3-- num:76 Thread-3-- num:75 Thread-3-- num:74 Thread-2-- num:83 Thread-2-- num:72 Thread-2-- num:71 Thread-2-- num:70 Thread-3-- num:73 Thread-1-- num:79 Thread-3-- num:68 Thread-3-- num:66 Thread-3-- num:65 Thread-2-- num:69 Thread-2-- num:63 Thread-2-- num:62 Thread-2-- num:61 Thread-2-- num:60 Thread-2-- num:59 Thread-2-- num:58 Thread-2-- num:57 Thread-2-- num:56 Thread-2-- num:55 Thread-2-- num:54 Thread-2-- num:53 Thread-2-- num:52 Thread-3-- num:64 Thread-1-- num:67 Thread-3-- num:50 Thread-2-- num:51 Thread-3-- num:48 Thread-1-- num:49 Thread-3-- num:46 Thread-2-- num:47 Thread-3-- num:44 Thread-1-- num:45 Thread-3-- num:42 Thread-2-- num:43 Thread-3-- num:40 Thread-1-- num:41 Thread-3-- num:38 Thread-2-- num:39 Thread-3-- num:36 Thread-1-- num:37 Thread-3-- num:34 Thread-2-- num:35 Thread-3-- num:32 Thread-1-- num:33 Thread-3-- num:30 Thread-2-- num:31 Thread-3-- num:28 Thread-1-- num:29 Thread-3-- num:26 Thread-2-- num:27 Thread-3-- num:24 Thread-1-- num:25 Thread-3-- num:22 Thread-2-- num:23 Thread-3-- num:20 Thread-1-- num:21 Thread-3-- num:18 Thread-2-- num:19 Thread-3-- num:16 Thread-1-- num:17 Thread-3-- num:14 Thread-2-- num:15 Thread-3-- num:12 Thread-1-- num:13 Thread-3-- num:10 Thread-2-- num:11 Thread-3-- num:8 Thread-1-- num:9 Thread-3-- num:6 Thread-2-- num:7 Thread-3-- num:4 Thread-1-- num:5 Thread-3-- num:2 Thread-2-- num:3 Thread-1-- num:1
2、继承Thread类
package src; public class ThreadClient extends Thread { public ThreadClient(String name) { super(name); } @Override public void run() { // TODO Auto-generated method stub for (int i = 0; i <= 10; i++) { System.out.println(currentThread().getName() + ":" + i); } } public static void main(String[] args) { ThreadClient thread1 = new ThreadClient("thread1"); ThreadClient thread2 = new ThreadClient("thread1"); ThreadClient thread3 = new ThreadClient("thread1"); thread1.start(); thread2.start(); thread3.start(); } }
输出结果
thread1:0 thread1:1 thread1:0 thread1:1 thread1:0 thread1:1 thread1:2 thread1:3 thread1:4 thread1:5 thread1:6 thread1:2 thread1:2 thread1:3 thread1:4 thread1:3 thread1:4 thread1:5 thread1:6 thread1:7 thread1:7 thread1:8 thread1:9 thread1:10 thread1:5 thread1:6 thread1:7 thread1:8 thread1:9 thread1:8 thread1:9 thread1:10 thread1:10
疑问:
为什么要重写 run方法?
run方法时存储线程所要运行的代码,不能在直接调用run方法,需要通过start方法来调用。
三、线程同步
场景:如果线程进行了sleep 操作时,其他线程对共享变量做了改变,会造成数据不同步问题。
package src; /** * * @author Shawn Wang * */ public class MyThread implements Runnable { private int j = 100; @Override public void run() { while (true) { if (j > 0) { try { Thread.sleep(1000);// 当前线程休眠1秒 } catch (Exception e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "-- num:" + j--); } else { break; } } } public static void main(String[] args) { MyThread mt = new MyThread(); Thread thread1 = new Thread(mt); Thread thread2 = new Thread(mt); Thread thread3 = new Thread(mt); thread1.start(); thread2.start(); thread3.start(); } }
输出结果:
Thread-1-- num:100 Thread-2-- num:99 Thread-3-- num:98 Thread-1-- num:97 Thread-3-- num:95 Thread-2-- num:96 Thread-1-- num:94 Thread-2-- num:92 Thread-3-- num:93 Thread-3-- num:91 Thread-2-- num:90 Thread-1-- num:90 Thread-3-- num:89 Thread-2-- num:88 Thread-1-- num:87 Thread-3-- num:86 Thread-2-- num:85 Thread-1-- num:85 Thread-3-- num:84 Thread-2-- num:83 Thread-1-- num:82 Thread-3-- num:81 Thread-1-- num:80 Thread-2-- num:80 Thread-3-- num:79 Thread-2-- num:77 Thread-1-- num:78 Thread-3-- num:76 Thread-2-- num:75 Thread-1-- num:74 Thread-2-- num:73 Thread-3-- num:71 Thread-1-- num:72 Thread-2-- num:70 Thread-1-- num:69 Thread-3-- num:69 Thread-2-- num:68 Thread-3-- num:66 Thread-1-- num:67 Thread-2-- num:65 Thread-1-- num:64 Thread-3-- num:64 Thread-2-- num:63 Thread-1-- num:62 Thread-3-- num:61 Thread-2-- num:60 Thread-3-- num:58 Thread-1-- num:59 Thread-2-- num:57 Thread-1-- num:56 Thread-3-- num:56 Thread-2-- num:55 Thread-1-- num:54 Thread-3-- num:54 Thread-2-- num:53 Thread-3-- num:52 Thread-1-- num:52 Thread-3-- num:51 Thread-2-- num:50 Thread-1-- num:51 Thread-3-- num:49 Thread-1-- num:48 Thread-2-- num:48 Thread-3-- num:47 Thread-1-- num:46 Thread-2-- num:45 Thread-1-- num:44 Thread-2-- num:42 Thread-3-- num:43 Thread-3-- num:40 Thread-1-- num:39 Thread-2-- num:41 Thread-2-- num:38 Thread-3-- num:37 Thread-1-- num:38 Thread-1-- num:36 Thread-2-- num:35 Thread-3-- num:36 Thread-1-- num:34 Thread-2-- num:33 Thread-3-- num:33 Thread-1-- num:32 Thread-3-- num:30 Thread-2-- num:31 Thread-1-- num:29 Thread-3-- num:29 Thread-2-- num:29 Thread-3-- num:28 Thread-1-- num:28 Thread-2-- num:28 Thread-1-- num:27 Thread-2-- num:26 Thread-3-- num:27 Thread-1-- num:25 Thread-2-- num:24 Thread-3-- num:24 Thread-1-- num:23 Thread-3-- num:22 Thread-2-- num:22 Thread-1-- num:21 Thread-3-- num:20 Thread-2-- num:20 Thread-1-- num:19 Thread-3-- num:18 Thread-2-- num:17 Thread-3-- num:16 Thread-1-- num:15 Thread-2-- num:14 Thread-2-- num:13 Thread-3-- num:12 Thread-1-- num:13 Thread-2-- num:11 Thread-1-- num:10 Thread-3-- num:10 Thread-2-- num:9 Thread-1-- num:7 Thread-3-- num:8 Thread-2-- num:6 Thread-3-- num:5 Thread-1-- num:5 Thread-2-- num:4 Thread-3-- num:3 Thread-1-- num:2 Thread-2-- num:1 Thread-1-- num:0 Thread-3-- num:-1
出现了负数。
解决加上同步锁synchronized
同步代码块的格式:
synchronized(对象){
需要被同步的代码;
}
package src; /** * * @author Shawn Wang * */ public class MyThread implements Runnable { private int j = 100; @Override public void run() { while (true) { synchronized (this) { if (j > 0) { try { Thread.sleep(1000);// 当前线程休眠1秒 } catch (Exception e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "-- num:" + j--); } else { break; } } } } public static void main(String[] args) { MyThread mt = new MyThread(); Thread thread1 = new Thread(mt); Thread thread2 = new Thread(mt); Thread thread3 = new Thread(mt); thread1.start(); thread2.start(); thread3.start(); } }