------- android培训、java培训、期待与您交流! ----------
多线程技术可以说是java中很重要的一个环节!
那么如何创建一个线程一般有两种方式:
1.继承Thread类,复写run方法
/*这是第一种方法开启一个线程:去继承Thread类
* 需要复写run方法
* */
class threadFristDemo extends Thread
{
public void run()
{
for(int i=0;i<10;i++)
{
System.out.println("this is frist"+i);
}
}
}
2.继承Runnable接口,复写run方法
/*这是第二种方法开启一个线程:去继承Runnable接口
*需要复写run方法
* */
class threadSecondDemo implements Runnable
{
public void run()
{
for(int i=0;i<10;i++)
{
System.out.println("this is second"+i);
}
}
}
那么如何开启线程呢?
//这里也说一下一般开发都是继承Runnable接口!因为这样的扩展性强。你可以让你的类去做你想做的事!
//比如在继承其他的类和接口!
/*这里是开启两个线程的实例,无论什么方法都必须去用start()开启!
* */
public static void threadDemo_0()
{
new threadFristDemo().start();
new Thread(new threadSecondDemo()).start();
}
一般都是调用都是start()方法区开启!千万不要调用run就好比是函数调用!
2.多线程编程
主要的解决因素为资源共享问题:1.可以用同步代码块
/*
* 该方法解决时用了同步代码块
class saleDemo implements Runnable
{
private static int ticket=100;
public void run() {
while(ticket>0)
{
show();
}
}
public synchronized void show()
{
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread()+"----"+ticket--);
}
}
*/
2.可以用同步函数来解决:
class saleDemo implements Runnable
{
private static int ticket=100;
Object obj = new Object();
public void run() {
while(ticket>0)
{
synchronized(obj)//注意这里能否用new Object()?不能,。这样会创建多个匿名Object
{
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread()+"----"+ticket--);
}
}
}
}
那么主函数可与这样写:
public static void threadDemo_1()
{
new Thread(new saleDemo()).start();//这里启动了3个线程
new Thread(new saleDemo()).start();
new Thread(new saleDemo()).start();
System.out.println(Thread.activeCount());//获取当前活动线程数!这里显示是4,也就是说还有一个主线程。
System.out.println(Thread.currentThread());//获取当前线程的信息
System.out.println(Thread.currentThread().getName());//获取当前线程名称
}
这里主要是由于线程的 资源共享问题的解决!
本例子虽然是创建了不同的对象,但是ticket为static的,所以内存中只有一份!也可作为demo
但是有一点不能验证synchronized函数方法!原因?你懂得!
解决资源共享问题的方法有1.synchronized(new Object()){}代码块2.synchronized函数
要注意他们的锁的不同!
3 .死锁问题:该死锁程序的主要前提是有两个锁!访问统一资源!当你的锁嵌套时会出现相互锁的情况! 我们在开发的时候要避免死锁!
public static void threadDemo_2()
{
deadLock dl = new deadLock();
new Thread(dl).start();
try {
Thread.sleep(100);//加不加这一句是出现死锁的关键!
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(dl).start();
}
class deadLock implements Runnable
{
private int ticket = 1000;
private boolean flag = true;
Object o1 =new Object();
Object o2 =new Object();
public void run()
{
show();
}
public void show()
{
if(flag)
{
flag = false;
synchronized(o1)
{
System.out.println("t-o1");
synchronized(o2)
{
System.out.println("t-o1-02");
System.out.println(ticket--);
}
}
}
else
{
synchronized(o2)
{
System.out.println("f-02");
synchronized(o1)
{
System.out.println("f-02-01");
System.out.println(+ticket--);
}
}
}
}
}
这样就会产生死锁,我们分析一下原因是:由于锁嵌套锁导致的,也就是说当有一个资源同时被两个锁给锁住了!
4.我们来看一个线程间通讯的例子,主要解决的问题是线程交替运行:
/*在生产和消费的问题中,最核心的就是数据共享和数据的交替使用!
* 数据共享可以用synchronized方法解决!
* 数据交换使用,可以用wait和notify来使用使得线程停止和解冻!
* 合理的使用函数就可以让数据交替合理的出现和使用
* */
class res //定义一个资源
{
private String sal = null;//商品名称
public static int count = 0; //商品编号
public boolean flag = false;//标志位
//jdk1.5之后产生了Lock方法,有ReentrantLock产生一个对象!便可以用lock和unlock加减锁
//而且可以有Condition对象,condition对象有await和singleAll方法
//使用十分方便!可以有单独解锁生产线程或消费线程的方法!
private Lock mylock;
private Condition cond_pro;
private Condition cond_con;
res()
{
this.mylock = new ReentrantLock();
this.cond_pro = mylock.newCondition();
this.cond_con = mylock.newCondition();
}
public void setSal(String sal)
{
this.sal =sal+count;
}
public String getSal()
{
return sal;
}
public void jdk5_pro()//jdk5.0之后的新方法
{
mylock.lock();
while(flag)
try {
cond_pro.await();//该方法的解冻必须由cond_pro.singleAll()来
} catch (InterruptedException e) {
e.printStackTrace();
}
count++;
setSal("mango");
System.out.println("pro----------"+getSal());
flag = true;
cond_con.signalAll();//只能解冻cond_con。await()的线程
mylock.unlock();
}
public void jdk5_con()
{
mylock.lock();
while(!flag)
try {
cond_con.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("con_eat:"+getSal());
flag = false;
cond_pro.signalAll();
mylock.unlock();
}
public synchronized void pro_sal()//生产方法
{
while(flag)//如果是1 个生产者就可以用if来判断
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
count++;
setSal("mango");
System.out.println("pro----------"+getSal());
flag = true;
this.notifyAll();//唤醒线程池中的全部等待线程
}
public synchronized void con_sal()//消费方法
{
while(!flag)//如果是1个消费者者就可以用if来判断
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("con_eat:"+getSal());
flag = false;
this.notifyAll();
}
}
//生产者类
class pro implements Runnable
{
private res r;//做一个共享资源!
pro(res r)
{
this.r = r;
}
@Override
public void run()
{
while(r.count<100)
r.jdk5_pro();
}
}
//消费者类
class consumer implements Runnable
{
private res r;
consumer(res r)
{
this.r = r;
}
@Override
public void run()
{
while(r.count<100)
{
r.jdk5_con();
}
}
}
这些代码中有两种产生方式:1.jdk1.5之前我们用wait和notify。2jdk1.5之后的Lock和Condition方式。
public static void main(String[] args) {
res r = new res();
pro p =new pro(r);
consumer c =new consumer(r);
new Thread(p).start();//注意的是两个线程通信和多个线程通讯时不同的
new Thread(p).start();
new Thread(c).start();
new Thread(c).start();
}
这是主函数的开启。代码中我们可以看出Lock锁更加方便,而且Condition对象可以分别解冻结状态!
注意几个线程函数:
1.interrupted()方法是把那些冻结状态的线程解冻!并产生一个异常
2.setDaemon()是把该线程设为守护线程,在没有其他线程存在时jvm不会管守护线程。
该方法必须在调用start之前!
3.join()是为了让别的等待他终止!如t1.join时候,必须等t1调用完事之后再执行其他!
4.yield()释放执行权
------- android培训、java培训、期待与您交流! ----------