多线程
线程是操作系统的一个重要概念,多线程是指程序中同时存在着好几个执行体,它们按几条不同的执行路线共同工作,独立完成各自的功能而互不干扰。例如:我们在听音乐的时候,还能同时上QQ聊天,还一边刷新浪微博,这都是多线程并发机制的功劳。
一.什么是进程,线程,它们的区别是什么?
进程是一个正在执行的程序,例如QQ,千千静听,360卫士等。
而线程是进程的某个单一顺序的控制流。一般是一个进程中包括多个线程。线程最大的特点是并发执行。由于线程的数据通常只有寄存器数据,以及一个程序执行时使用的堆栈,所以线程切换会非常快,以致于它们互相切换使我们感觉不到差别,令我们觉得始终是一个程序为我们服务。
如图:多线程
二.关于Java中多线程的基础知识
1.Java虚拟机启动时就有一个进程java.exe
2.最开始的时候jvm会开始调用main 线程先,然后在调用一下代码中的线程
3.写线程有两种方法:
- 线程可以直接继承java.lang.Thread,然后覆盖run方法来实现自己的功能,再调用线程的start方法来启动线程。
- 可以实现Runnable接口,必须实现run接口。在调用时再将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。如new Thread(new RunnableClass()).start();
- 推荐使用第二种方法,因为java本身不支持多继承,利用接口可用性较强
4.线程如果没哟自定义名字通常使用默认名字 Thread-编号(编号从0开始)。
如图两种实现方法
继承Thread (其实我们看源代码可以知道,Thread类也实现了Runnable接口,因此也实现了run方法)
class Demo extends Thread
{
public void run()
{
System.out.println("创建线程");
}
}
Demo d = new Demo();//创建好一个线程。
d.start();//开启线程并执行该线程的run方法。
实现Runnable接口
class Demo implements Runnable
{
public void run()
{
System.out.println("创建线程");
}
}
Demo d = new Demo();
new Thread(d).start();//创建好一个线程,开启线程并执行该线程的run方法。
三 线程的生命周期,如图
1.创建新线程,调用start( )方法进入运行状态,此时应该有两个状态,当线程分配到CPU 资源时,它才有资格去运行,否则,线程进入堆栈,处于阻塞状态,等到分配到CPU资源在运行。
2.冻结状态,是运行状态通过sleep(time)或wait()方法使它暂时处于冻结状态,当睡眠时间够了,或者由程序员定义什么时候唤醒notify()方法改变状态。
3.销毁状态,此时释放CPU资源,线程灭忙。这有两个原因:一是正常运行的线程完成了它的全部工作。二是线程被强制终止。
注意:并不是要进入销毁状态才会释放CPU资源,CPU资源分配是不确定,这看哪个线程先抢到资源。
四. 同步问题
代码是一条一条地执行,当执行到某句时候,线程A还没有执行到下一句时被抢了线程B的资源,线程B就执行下去包括线程A的没有执行的代码,此时线程B释放资源,线程A重新获得资源,继续执行,但因为两条线程共享了同一个数据,会出现问题。
class test_thread implements Runnable{
private int num=50;
public void run() {
// TODO 自动生成的方法存根
while(num>0)
{
try {
Thread.sleep(10); //A执行到这里,被B抢去了CPU资源,B继续运行,当B刚好等于1时,减减,num为0,此时A不再判断而输出0;
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"num="+num--);
}
}
}
public class Demo_thread {
public static void main(String[] args) {
// TODO 自动生成的方法存根
test_thread t1=new test_thread();
new Thread(t1).start();
new Thread(t1).start();
}
}
输出:......
Thread-0num=1
Thread-1num=0
解决方法:引入锁的概念
synchronized:当synchronized关键字修饰一个方法的时候,该方法叫做同步方法。
1.当方法用synchronized 时,就像加上了一把锁,线程A进去了,只有等到线程A执行完这个程序块,线程B才能进入去执行。解决了共享同一个数据的问题。就像我们正常谈恋爱一样,当一对情侣正在热恋的时候,我们就只能等他们分手时才能追求女孩,这个"恋爱锁"是只能等他们分手后才解锁,我们(线程B)才能追求,成功后我们也是加了一把锁,别人也干扰不进来。
synchronized(对象)
{
需要被同步的代码
}
2.加同步代码块的地方首先要明确两点
- 必须有两个或两个以上的线程
- 必须多个线程使用的是同一把锁
public class P03_11 implements Runnable {
static Object S1 = new Object(), S2 = new Object();
public void run() {
if (Thread.currentThread().getName().equals("th1")) {
synchronized (S1)
{
System.out.println("线程1锁定S1");
try {
Thread.sleep(1000);
} catch (Exception ex) {
}
synchronized (S2) {
System.out.println("线程1锁定S2");
}
}
} else {
synchronized (S2) {
System.out.println("线程2锁定S2");
}
synchronized (S1) {
System.out.println("线程2锁定S1");
}
}
}
public static void main(String[] args) {
Thread t1 = new Thread(new P03_11(), "th1");
Thread t2 = new Thread(new P03_11(), "th2");
t1.start();
t2.start();
}
}