---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! --------------------
一、线程的概念
线程就是进程中的一个独立的单元,线程控制着线程的执行。一个进程中至少是有一个线程的。
线程的一个特性:随机性。因为谁执行都是CPU说的算。
二:如何定义线程
(1)继承方式
第一步:继承Thread类
第二步:重写run方法;这是为了将自定义代码存在run方法中让线程运行
第三步:调用线程的start方法(启动线程,调用run方法)
(2)实现方式
第一步:实现Runnable接口
第二步:覆盖Runnable中的run方法
第三步:通过Thread类建立线程的对象
第四步:将Runnable的子类的对象作为参数传给Thread类的构造函数
第五步:调用Thread 的start方法,启动线程调用Runnable子类的run方法
1、两种的区别:
Java只支持单继承,也就是说一个类只能继承一个父类,如果此类只需要继承Thread的话那么继承与实现是没有区别的。如果此类还要继承其他类的话这时候就不能使用继承方式了。就只能使用实现Runnable接口的方式。所以实现方式可以避免继承方式的局限性,建议使用实现方式。
2、下面是一个这两种方式的实现以及一些线程的小操作
class Demo1 implements Runnable
{
public void run()
{
for(int y=0;y<10;y++)
{
System.out.println(Thread.currentThread().getName()+" y"+y);
}
}
}
class Demo extends Thread
{
public void run()
{
for(int i=0;i<10;i++)
{
System.out.println(Thread.currentThread().getName()+" i"+i);//获取当前线程的名称
}
}
}
public class Treadtest
{
public static void main(String[] args)
{
Demo d=new Demo();
d.start();//启动线程
Demo1 d1=new Demo1();
Thread td=new Thread(d1);//建立Thread线程对象,并把对象d1作为参数
td.start();
for(int i=0;i<10;i++)
{
System.out.println("Main run...."+i);
}
}
}
三、多线程的同步
当多线程多条语句都在操作同一共享数据时候,一个线程只对多条语句执行了一部分,另外一个线程参与执行,这样就造成了共享数据的错误。
这样子java就提供了同步的方法来解决这个问题
1、同步的前提:
必须要有两个或者两个以上的线程
必须是多个线程在使用同一个锁
2、同步的两种方式
同步代码块
synchronized(对象也就是锁)
{
需要被同步的代码。
}
同步函数:把synchronized 当做修饰符修饰方法
class Ticket2 implements Runnable//1.定义实现Runnable借口的类
{
static int ticket=100;
public void run()//2‘覆盖接口中的run方法
{
while(ticket>0)
{
show();
/* synchronized(this)
同步代码块的方式
{
if(ticket>0)
System.out.println(Thread.currentThread().getName()+"........"+ticket--);
}*/
}
}
public static synchronized void show()//同步函数 如果是静态的话,同步方法使用的锁是字节码文件对象
//也就是ticket.class 如果不是静态的话就是this.
{
if(ticket>0)
{
System.out.println(Thread.currentThread().getName()+"........"+ticket--);
}
}
}
public class Threaddingyi
{
public static void main(String[] args)
{
Ticket2 t=new Ticket2();
new Thread(t).start();//通过Thread类建立线程并将Runnable的子类对象作为参数传递给Thread
//后调用Thread类中的start方法开启线程,执行Runnable的子类中的run方法
new Thread(t).start();
new Thread(t).start();
new Thread(t).start();
}
}
四、线程间的通信
多线程在操作同一资源,但是操作的方式不一样
class res
{
private String name;
private String sex;
private boolean flag=false;
public synchronized void set(String name,String sex)
{
if(flag)
try{this.wait();}
catch(Exception e)
{
}
this.name=name;
this.sex=sex;
flag=true;
this.notify();
}
public synchronized void prit()
{
if(!flag)
try{this.wait();}
catch(Exception e){}
System.out.println(name+"....."+sex);
flag=false;
this.notify();
}
}
class Input implements Runnable
{
private res r;
Input(res r)
{
this.r=r;
}
public void run()
{
int x=0;
while(true)
{
if(x==0)
System.out.println("tt"+"....."+"feman");
else
System.out.println("李四"+"....."+"男");
x=(x+1)%2;
}
}
}
class out implements Runnable
{
private res r;
out(res r)
{
this.r=r;
}
public void run()
{
r.prit();
}
}
class DengdaiTest
{
public static void main(String[] args)
{
res r=new res();
Input in=new Input(r);
out ou=new out(r);
Thread t=new Thread(in);
Thread t1=new Thread(ou);
t1.start();
t.start();
}
}
但是此时会出现一个问题,如果同时多个线程操作Input,多个线程操作in的话就会出现问题。如输入两个却只打印一个的情况。所以我们就有了唤醒等待的出现
唤醒等待机制:
1、Wait()notify()要使用在同步中,因为要对持有锁的线程操作
2、我们可以将synchronized替换成Lock操作,将wait,notify,notifyAll替换成condition对象。该对象可以对Lock锁进行获取。这样一个锁可以对应多个condition对象。而第一种的同步只能对应一个wait(),notify()。
操作如下:Lock lock=new ReentrantLock();
Condition con_shengc=lock.newCondition();
下面我们通过一个生产消费者的例子说明
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class shengchang
{
private String name;
private boolean flag=false;
private Lock lock=new ReentrantLock();
private Condition con_shengc=lock.newCondition();
private Condition con_xiaofei=lock.newCondition();
public void set(String name) throws InterruptedException
{
lock.lock();
try{
while(flag)
con_shengc.await();
this.name=name;
System.out.println(name+"生产者.....");
flag=true;
con_xiaofei.signal();
}
finally
{
lock.unlock();
}
}
public void prit()throws InterruptedException
{
lock.lock();
try{
while(!flag)//这边如果用if的话会出现多个生产者而只有一个消费者的情况
con_xiaofei.await();
System.out.println(name+"消费者...............................");
flag=false;
con_shengc.signal();
}
finally {
lock.unlock();
}
}
}
class produce implements Runnable
{
private shengchang sc;
produce(shengchang sc)
{
this.sc=sc;;
}
public void run() {
while(true)
try {
sc.set("商品");
} catch (InterruptedException e) {
}
}
}
class xiaofei implements Runnable
{
private shengchang sc;
xiaofei(shengchang sc)
{
this.sc=sc;;
}
public void run()
{
while(true)
try {
sc.prit();
} catch (InterruptedException e) {
}
}
}
public class ProudceDemo {
public static void main(String[] args)
{
shengchang sc=new shengchang();
new Thread(new produce(sc)).start();
new Thread(new produce(sc)).start();
new Thread(new xiaofei(sc)).start();
new Thread(new xiaofei(sc)).start();
}
}
五:停止线程
停止线程就是要使run方法结束。但是当线程都处于冻结状态的时候,那么线程就不会结束。这时我们需要对冻结状态进行清除,强制让线程恢复到运行状态来,这样就可以操作让线程结束。Thread类提供了interrupt方法实现
class stop implements Runnable
{
private boolean flag=true;
public synchronized void run() {
while(flag)
{
try{
wait();
}
catch(InterruptedException e){
System.out.println(Thread.currentThread().getName()+"发生异常.....");
flag=false;
}
}
}
}
public class StopThread
{
public static void main(String[] args) throws InterruptedException
{
stop s=new stop();
Thread t=new Thread(s);
Thread t1=new Thread(s);
t.start();
t1.start();
for(int i=0;i<100;i++)
{
t.interrupt();//使线程一恢复到运行状态,使得t不在处于冻结状态,这样就可以结束线程
t1.interrupt();
System.out.println(i);
}
System.out.println("oooo");
}
}
六:Thread的一些其他方法
1. setDaemon方法:在启动线程之前调用 被setDaemon标识的是后台线程,当前台线程结束后,后台进程自动结束。
2. join方法:当A线程执行到了B线程的join方法的时候,A线程等待,等B线程执行完A线程在执行。
3. yield方法:临时停止当前的线程。
------------------------ ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ---------------------
-详细请查看:http://edu.csdn.net