---------------------- android培训、java培训、期待与您交流! ----------------------
一、进程
进程是在执行中的程序,每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元。
二、线程
线程是进程中的一个独立的控制单元,线程在控制着进程的执行。一个进程中至少有一个线程。
三、自定义多线程
创建新执行线程的两种方法:一种方法是将类声明为Thread的子类。该子类应重写Thread类的run方法。用于存储线程要运行的代码。定义多线程的步骤:
1、定义类继承Thread;
2、覆写run方法;
目的是:将自定义的代码存储在run方法中,让线程运行。
3、创建对象就是新建一个线程;
4、调用start方法启动线程,start作用是启动线程,调用run方法。
事例:
class Demo extends Thread
{
public void run()
{
System.out.println("demo run:);
}
}
class ThreadDemo
{
public static void main(String[] args)
{
Demo d = new Demo();// 就创建了一个线程
d.start();//让线程开启并执行线程的run方法
System.out.println("Hello World!");
}
}
注意:在某一时刻,只能有某一个程序在运行(多核除外),CPU在各个程序之间在做着快速的切换,已达到看上去同时运行的效果。这就是多线程的一个特性:随机性。
class Demo extends Thread
{
public void run()
{
for(int x=0;x<60;x++)
System.out.println(this.getName()+"demo run:");//获取线程名称,
}
}
class ThreadDemo1
{
public static void main(String[] args)
{
Demo d = new Demo();// 就创建了一个线程
Demo d1 = new Demo();
d.start();
d1.start();
for (x=0;x<70;x++ )
{
System.out.println(Thread.currentThread()+"Hello World!");
// 获取线程名称
}
}
}
创建线程的另一种方法是声明实现Runnable接口的类。该类然后实现run方法。然后可以分配该类的实例。步骤:
1、定义类实现Runnable接口;
2、覆盖Runnable接口中的run()方法;
目的:将线程要运行的代码放在run方法中
3、通过Thread类建立线程对象;
4、将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数;
原因:因为自定义的run方法所属的对象时Runnable接口的子类对象,多以要让线程去执行指定对象的run方法,就必须明确该run方法 所属的对象。
5、调用Thread类的start方法开启线程并调用Runnable接口子类的run方法。
四、继承方式和实现方式的区别:
1、实现方式好处:避免单继承的局限性,还可以把run方法中的数据共享。再定义线程时,建议使用实现方式。
2、两种方式的区别:继承Thread:线程代码存放在Thread子类的方法中。而实现Runnable:线程代码存放在Runnable接口子类的run方法中。
class Ticket implements Runnable
{
private int tick=100;
public void run()
{
while(true)
{
if(tick>0)
{
System.out.println( Thread.currentThread()+"..."+tick--);
}
}
}
}
class TicketDemo
{
public static void main(String[] args)
{
Ticket t=new Ticket();
Thread t1=new Thread(t);//创建一个线程
Thread t2=new Thread(t);//创建一个线程
Thread t3=new Thread(t);//创建一个线程
Thread t4=new Thread(t);//创建一个线程
t1.start();
t2.start();
t3.start();
t4.start();
}
}
五、多线程的安全问题
(一)同步代码块
class Ticket implements Runnable
{
private int tick=100;
Object obj = new Object();
public void run()
{
while(true)
{
/*
当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,
还没有执行完,而另一个线程参与进来执行,导致共享数据的错误。解决办法
对多条操作共享数据的语句,只能让一个线程执行完,在执行过程中,其他线程
不可以参与执行。解决办法就是同步代码块:
synchronized(对象)
{
需要被同步的代码;
}
*/
//同步的前提:
//必须要有两个或者两个以上的线程;必须是多个线程使用同一个锁
synchronized(obj)//同步代码块中的锁。持有锁的线程可以在同步中执行。
{ //没有持有锁的线程即使获取可cpu的执行权,也进不去
//因为没有获得锁
if(tick>0)
try
{
Thread.sleep(10)//让线程睡10ms该方法有异常抛出,由于接口没有抛异常
//所以子类必须处理
}
catch (Exception e)
{
}
System.out.println(Thread.currentThread()+"..."+tick--);
}
}
}
}
}
class TicketDemo
{
public static void main(String[] args)
{
Ticket t=new Ticket();
Thread t1=new Thread(t);//创建一个线程
Thread t2=new Thread(t);//创建一个线程
Thread t3=new Thread(t);//创建一个线程
Thread t4=new Thread(t);//创建一个线程
t1.start();
t2.start();
t3.start();
t4.start();
}
}
同步代码块的好处:解决了多线程的安全隐患。
同步代码块的弊端:降低了程序执行的效率。
(二)同步函数
如何找问题:
1、明确那些代码是被多线程运行的代码;
2、明确共享数据;
3、明确多线程运行代码中哪些语句是操作共享数据的。
class Bank
{
private int sum;
//Object obj = new Object();
public synchronized void add(int n)//同步函数的用法
{
sum=sum+n;
try{Thread.sleep(10);}catch(Exception e){}
System.out.println("sum="+sum);
}
}
class Cus implements Runnable
{
private Bank b= new Bank();
public void run()
{
for (int x=0;x<3;x++ )
{
b.add(100);
}
}
}
class BankDemo
{
public static void main(String[] args)
{
Cus cus = new Cus();
Thread t1 = new Thread(cus);
Thread t2 = new Thread(cus);
t1.start();
t2.start();
}
}
同步函数的锁:函数需要被对象调用,那么函数都有一个所属对象的引用this,所以同步函数所使用的锁是this。
(三)静态同步函数
静态进内存时,内存中还没有本类对象,但是一定有该类对应的字节码文件对象,
类名.class 该对象的类型是Class。那么静态的同步方法使用的锁是该方法所在类的字节码文件对象,类名.class。
//单例设计模式中的懒汉式
class Single
{
private static Single s=null;
private Single(){}
public static Single getInstnce()
{
if(s==null)
{
synchronized(Single.class)
//使用的锁是该方法所属对象的字节码对象
{
if(s==null)
s= new Single();
}
}
return s;
}
}
class SingleDemo
{
public static void main(String[] args)
{
}
}
(四)死锁
同步中嵌套着同步,而且这些同步使用不是同一个锁。
事例:
class test implements Runnable
{
private boolean flag;
test(boolean flag)
{
this.flag=flag;
}
public void run()
{
if(flag)
{
while(true)
{
synchronized(MyLock.locka)
{
System.out.println("if locka");
synchronized(MyLock.lockb)
{
System.out.println("if lockb");
}
}
}
}
else
{
while(true)
{
synchronized(MyLock.lockb)
{
System.out.println("else lockb");
synchronized(MyLock.locka)
{
System.out.println("else locka");
}
}
}
}
}
}
class MyLock
{
static Object locka =new Object();
static Object lockb =new Object();
}
class DeadLock
{
public static void main(String[] args)
{
Thread t1 = new Thread(new test(true));
Thread t2 = new Thread(new test(false));
t1.start();
t2.start();
}
}
六、线程间的通信
其实就是多个线程在操作同一个资源,但是操作的动作不同。
(一)等待唤醒机制
class Res
{
String name;
String sex;
boolean flag=false;
}
class Input implements Runnable
{
private Res r;
Input(Res r)
{
this.r=r;
}
public void run()
{
int x= 0;
while(true)
{
synchronized(r)
{
if(r.flag)
try{r.wait();}catch(Exception e){}//让线程等待
if(x==0)
{
r.name="mike";
r.sex="man";
}
else
{
r.name="丽丽";
r.sex="女";
}
x=(x+1)%2;
r.flag=true;
r.notify();//唤醒等待的进程
}
}
}
}
class Output implements Runnable
{
private Res r;
Output(Res r)
{
this.r=r;
}
public void run()
{
while(true)
{
synchronized(r)
{
if(!r.flag)
try{r.wait();}catch(Exception e){}
System.out.println(r.name+"...."+r.sex);
r.flag=false;
r.notify();
}
}
}
}
class InputOutputDemo
{
public static void main(String[] args)
{
Res r= new Res();
Input in = new Input(r);
Output out = new Output(r);
Thread t1 = new Thread(in);
Thread t2 = new Thread(out);
t1.start();
t2.start();
}
}
/*
wait(),notify(),notifyAll()都是用在同步中,因为要对持有监视器(锁)的线程操作,
所以要使用在同步中,因为只有同步才具有锁。
为什么这些操作线程的方法要定义在Object类中呢?
因为这些方法在操作同步中的线程时,都必须要标示它们所操作线程持有的锁,
只有在同一个锁上的被等待的线程,才可以被同一个锁上的notify()唤醒。不可以对不同锁中
的线程进行唤醒。也就是说,等待和唤醒必须是同一个锁。而所可以是任意的,所以可以被任意
对象调用的方法都定义在Object类中。
*/
(二)生产消费者问题
class Resource
{
private String name;
private int count;
private boolean flag= false;
public synchronized void set(String name)
{
while(flag)
try{this.wait();}catch(Exception e){}//让线程等待
this.name=name+"___________________-__"+count++;
System.out.println(Thread.currentThread().getName()+"生产"+this.name);
flag=true;
this.notifyAll();
}
public synchronized void out()
{
while(!flag)
try{this.wait();}catch(Exception e){}//让线程等待
//获取当前线程的名字和资源的名字
System.out.println(Thread.currentThread().getName()+"消费"+this.name);
flag=false;
this.notifyAll();
}
}
class producer implements Runnable
{
private Resource r;
producer(Resource r)
{
this.r=r;
}
public void run()
{
while(true)
r.set("商品");
}
}
class consumer implements Runnable
{
private Resource r;
consumer(Resource r)
{
this.r=r;
}
public void run()
{
while(true)
r.out();
}
}
class ConsumerProducerDemo
{
public static void main(String[] args)
{
Resource r = new Resource();
producer pro=new producer(r);
consumer con = new consumer(r);
Thread t1=new Thread(pro);
Thread t2=new Thread(pro);
Thread t3=new Thread(con);
Thread t4=new Thread(con);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
七、1.5新特性
(一)加锁解锁(lock(),unlock())
提供显式的锁机制:
import java.util.concurrent.locks.*;
class Resource
{
private String name;
private int count;
private boolean flag= false;
private Lock lock=new ReentrantLock();
private Condition condition_pro=lock.newCondition();
private Condition condition_con=lock.newCondition();
public void set(String name)throws InterruptedException
{
lock.lock();
try
{
while(flag)
condition_pro.await();//让线程等待
this.name=name+"___________________-__"+count++;
System.out.println(Thread.currentThread().getName()+"生产"+this.name);
flag=true;
condition_con.signal();
}
finally
{
lock.unlock();
}
}
public void out()throws InterruptedException
{
lock.lock();
try
{
while(!flag)
condition_con.await();//让线程等待
//获取当前线程的名字和资源的名字
System.out.println(Thread.currentThread().getName()+"消费"+this.name);
flag=false;
condition_pro.signal();
}
finally
{
lock.unlock();
}
}
}
class producer implements Runnable
{
private Resource r;
producer(Resource r)
{
this.r=r;
}
public void run()
{
while(true)
try
{
r.set("商品");
}
catch (InterruptedException e)
{
}
}
}
class consumer implements Runnable
{
private Resource r;
consumer(Resource r)
{
this.r=r;
}
public void run()
{
while(true)
try
{
r.out();
}
catch (InterruptedException e)
{
}
}
}
class ConsumerProducerDemo1
{
public static void main(String[] args)
{
Resource r = new Resource();
producer pro=new producer(r);
consumer con = new consumer(r);
Thread t1=new Thread(pro);
Thread t2=new Thread(pro);
Thread t3=new Thread(con);
Thread t4=new Thread(con);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
二、停止线程
停止线程只有一种方法,那就是让run方法结束。开启多线程运行,运行代码通常是循环结构。只要控制循环,就可以让run方法结束,也就是让线程结束。特殊情况下,当线程处于冻结状态,就不会读取到标记。就需要 interrupt清除冻结状态的线程。
守护线程setDaemon(true)前台线程结束后,保护线程立即结束。
join()向主线程要执行权。当A线程执行到了B线程的join方法时,A就会等待,等B线程都执行完,A线程才会执行。用于临时加入线程。
yield()临时暂停线程
---------------------- android培训、java培训、期待与您交流! ----------------------