---------------------- <a href="http://www.itheima.com"target="blank">ASP.Net+Unity开发</a>、<a href="http://www.itheima.com"target="blank">.Net培训</a>、期待与您交流! --------------------
一、线程概述
在操作系统中,每个运行着的应用程序都至少有一个后台运行程序,叫做进程,它是独占一定内存空间的程序片段。
一个进程当中可能会有多条执行路径(程序从开始执行到结束执行这一途径)。线程就是进程中的一个独立的控制单元。一个进程中至少有一个线程,线程在控制着进程的执行。
在Java语言中,main方法是程序入口,通常称为主线程,其他线程则称为子线程。
注意:程序中控制单元或执行路径每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或者叫一个控制单元。
二、在程序中如何定义一个线程
1.继承Thread类方式
实例代码1如下:
<span style="font-family:SimSun;font-size:14px;">package com.demo.thread;
/**
* Main方法类
*/
public class Demo {
/**
* @param args
*/
public static void main(String[] args) {
ThreadDemo td=new ThreadDemo();
td.start();//第三步:调用Tread类中的start()方法,启动线程并调用run()方法
for(int x=0;x<60;x++){
System.out.println("demo run"+x);
}
Thread t=new Thread();
/*
* t.run()和t.start()区别:
t.run();//仅仅是对象调用方法。而线程创建了,但并没有运行
t.start();//开启线程并执行该线程的run方法
*/
}
}
/**
* 线程类
* 沿袭父类功能,重写父类run方法。
*/
class ThreadDemo extends Thread{//第一步:定义类继承Thread类
@Override
public void run(){//第二步:重写Tread类中的run()方法,目的是为了将自定义的代码存储在run方法中,用于运行。
for(int x=0;x<60;x++){
System.out.println("ThreadDemo RUN"+x);
}
}
}</span>
2.实现Runnable方式
步骤:
1.定义类实现Runnable接口
2.覆盖Runnable接口中的run方法。
3.通过Thread类创建线程对象。
4.将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。
5.调用Thread类的start方法开启线程并调用Runnable接口子类的run方法。
示例代码2如下:
<span style="font-family:SimSun;font-size:14px;">/**
* 线程类
* 需求:简单的卖票程序。多个窗口同时买票。
*/
class Ticket implements Runnable{
private int tick=100;
Object obj=new Object();
@Override
public void run(){
while(true){
synchronized (obj) {//同步锁,火车卫生间标准同步
if(tick >0){
System.out.println(Thread.currentThread().getName()+"......sale : "+ tick--);
}
}
}
}
}
/**
* 运行类
*/
public class TicketDemo{
public static void main(String[] args) {
Ticket t=new Ticket();//创建线程的是Thread类对象或Thread子类对象,而当前对象只是实现了接口,没有继承Thread,所以该对象没有创建线程。
Thread th1=new Thread(t);
Thread th2=new Thread(t);
Thread th3=new Thread(t);
Thread th4=new Thread(t);
th1.start();
th2.start();
th3.start();
th4.start();
}
}</span>
疑问1:为什么要将Runnable接口的子类对象传递给Thread的构造函数?
因为,自定义的run方法所属的对象是Runnable接口的子类对象。
所以要让线程去调用指定对象的run方法,就必须明确该run方法所属对象。
疑问2:实现接口方式和继承方式有什么区别呢?
区别一:实现方式避免了单继承的局限性。推荐使用接口方法。
例子,Student继承Persion类实现Runnable接口,表示Student类中既有Persion的类似行为,又可以写多线程的代码供jvm调用。
如果Student继承Thread类,和Persion类似的行为必须全部copy一份,因为java不允许多重继承,这样就造成了代码大量冗余,违反了重用原则。
区别二:
继承Thread:线程代码存放Thread子类run方法中。
实现Runnable,线程代码存放在接口的子类的run方法中。
三、线程的状态
共5个状态:创建、运行、阻塞、消亡、冻结(睡眠或等待)
说明:new Thread()方法使得线程处于已创建状态,然后由start()方法使得线程处于运行状态,对于运行着的线程可以使用sleep()方法或wait()方法使得线程处于冻结状态
最后可由notify()方法使得线程具备了执行资格,但不一定有执行权限,处于抢CPU资源时期,此时的该线程的状态称为临时状态或阻塞状态,最后可以使用stop()方法使得线程处于消亡状态,即线程结束运行。
四、线程同步块和同步函数
1.语法说明:
<span style="font-family:SimSun;font-size:14px;">synchronized(对象)
{
需要被同步的代码,就是线程之间共享数据
}</span>
因为在一个进程中多个线程之间是共享内存数据的,例如上述实例代码2中的下述代码:
<span style="font-family:SimSun;font-size:14px;">synchronized (obj) {//同步锁,火车卫生间标准同步
if(tick >0){
System.out.println(Thread.currentThread().getName()+"......sale : "+ tick--);
}
}</span>
如果4个线程共同执行这段代码,就有可能造成tick的值变为负数,假设此时的tick值为1,由线程1执行到if语句进行判断,此时判断通过,在将要打印输出方法时,CPU资源被线程2抢占,则线程2执行if语句进行判断,又因为线程1判断语句没有执行,所以此时tick的值还是1,那么线程2也通过了判断,在刚要执行输出语句时,同理CPU资源又被线程3抢占,并直接执行输出语句,此时输出值为1,但tick的实际值为0,就在同时线程1有抢占了CPU资源,获得了执行权限,则打印tick值为0,此时tick内存中实际值为-1,最后由线程2打印值为-1,但要注意,此时内存中tick的存储值为-2。这样就导致了数据不同步,票数出现了负数,与现实生活中不符。而使用synchronized同步块就解决了这个问题。
注意: 添加同步的前提是(1).必须要有两个或两个以上的线程。(2).必须是多个线程使用同一个锁。
2.原理
在每个线程执行到同步块内容时,对该同步块加上锁机制,在该线程没有执行结束之前,其他任何线程都无法执行该加锁的同步块内容,即使获得执行权限也只能等待当前线程执行结束后,释放了锁,其他线程才有可能进入同步块内部执行。这就保证了数据安全性。
3.同步块的利与弊
对象如同锁。持有锁的线程可以在同步中执行。没有持有锁的线程即使获取cpu的执行权,也进不去,因为没有获取锁。( 火车上的卫生间-----经典)
好处:解决了多个线程数据安全问题。
弊端:多个线程需要判断锁,较为消耗资源
锁说明:
同步函数,就是在函数声明前加synchronized关键字。同步函数用的锁是this
如果同步函数被static关键字修饰后,则它使用的锁是该类的字节码对象。
4.单例模式的懒汉式和饿汉式代码
//饿汉式
class SingleOne {
private static final SingleOne s = new SingleOne();
private SingleOne() {
}
public static SingleOne getInstance() {
return s;
}
}
//懒汉式
class Single{
private static Single s=null;
private Single(){}
public static Single getInstance(){
if(s==null){
synchronized(Single.class){
if(s==null){//多线程时存在安全隐患,双重判断能减少锁的判断次数
s=new Single();
}
}
}
return s;
}
}
---------------------- <a href="http://www.itheima.com"target="blank">ASP.Net+Unity开发</a>、<a href="http://www.itheima.com"target="blank">.Net培训</a>、期待与您交流! ----------------------
详细请查看:<a href="http://www.itheima.com" target="blank">www.itheima.com</a>