守护线程
o.必须通过setDaemon(true)进行设置;a.所谓守护线程就是运行在程序后台的线程,程序的主线程Main不会是守护线程.
b.默认产生的线程全部是Non-daemon线程.
c.主线程main一结束,jvm停止了,守护线程也就结束了。(会伴随着main消亡,而不是一起而生)
/*stop方法已经过时。
如何停止线程?
只有一种,run方法结束。
开启多线程运行,运行代码通常是循环结构。
只要控制住循环,就可以让run方法结束,也就是线程结束。
特殊情况:
当线程处于了挂起状态。
就不会读取到标记。那么线程就不会结束。
a.Thread类提供该方法 interrupt();
b.通过setDaemon(true);转为守护线程
*/
class StopThread implements Runnable
{
private boolean flag =true;
public void run()
{
while(flag)
{
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"....run" );
}
}
public void changeFlag()
{
flag = false;
}
}
class StopDemo
{
public static void main(String[] args)
{
StopThread st = new StopThread();
Thread t1 = new Thread(st);
Thread t2 = new Thread(st);
t1.setDaemon(true);//使用守护线程
t2.setDaemon(true);
t1.start();
t2.start();
int num = 0;
while(true)
{
if(num++ == 60)
{
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
//st.changeFlag();
//t1.interrupt();
//t2.interrupt();
break;
}
System.out.println(Thread.currentThread().getName()+"......."+num);
}
System.out.println("over");
}
}
sleep与yield的区别
不同点:a.Thread.sleep(long millis)必须带有一个时间参数的<------>yield()不带参数的
b.sleep() 方法不管优先级高低,线程获得运行机会<------>yield()方法只能让同优先级的线程有执行的机会。
c.sleep()会抛出InterruptedException异常,而yield不会抛出异常。
d.sleep比yield方法有更好的可移植性,通常,不要依靠yield控制并发线程的执行。
相同点:都不会释放锁标志。
A.join(1000) 等一秒后,让出当前线程(不管有没有执行完)
相同点:都不会释放锁标志。
join:
A.join()只有A线程执行完,才能执行其他线程;A.join(1000) 等一秒后,让出当前线程(不管有没有执行完)
class JoinThread implements Runnable
{
public void run()
{
for(int i = 0; i < 30; i++){
if(i++ % 10 == 0){
try {
Thread.currentThread().join(100);
System.out.println(Thread.currentThread().getName());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
public class JoinDemo
{
public static void main(String[] args)
{
JoinThread st = new JoinThread();
Thread t1 = new Thread(st);
Thread t2 = new Thread(st);
t1.start();
t2.start();
}
}
//----------结果----------
Thread-1
Thread-0
Thread-0
Thread-1
Thread-1
Thread-0
案例 --银行 --生产者和消费者
/*
需求:
银行有一个金库。
有两个用户分别存200,每次存100,存2次。
目的:该程序是否有安全问题,如果有,如何解决?
如何找问题:
1,明确哪些代码是多线程运行代码。
2,明确共享数据。-->(钱)
3,明确多线程运行代码中哪些语句是操作共享数据的。
*/
class Bank
{
private int sum;
public synchronized void add(int n)
{
//synchronized(this){
sum = sum + n;
try{Thread.sleep(10);}catch(Exception e){}
System.out.println("sum="+sum);
//}
}
}
class Manipulation implements Runnable
{
private Bank b = new Bank();
public void run()
{
for(int x=0; x<2; x++)
{
b.add(100);
}
}
}
class BankDemo
{
public static void main(String[] args)
{
Manipulation c = new Manipulation();
Thread t1 = new Thread(c);
Thread t2 = new Thread(c);
t1.start();
t2.start();
}
}
/*
对于多个生产者和消费者。
为什么要定义while判断标记。
原因:让被唤醒的线程再一次判断标记。
为什么定义notifyAll,
因为需要唤醒对方线程。
因为只用notify,容易出现只唤醒本方线程的情况。导致程序中的所有线程都等待。
*/
package com.cwk.inner;
class Resource
{
private String name;
private int count = 1;
private boolean flag = false;
public synchronized void set(String name)
{
while(flag)
try{this.wait();
Thread.sleep(500);
}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{wait();
}catch(Exception e){}
System.out.println(Thread.currentThread().getName()+"....消费者..........."+this.name);
flag = false;
this.notifyAll();
}
}
class Producer implements Runnable
{
private Resource res;
Producer(Resource res)
{
this.res = res;
}
public void run()
{
while(true)
{
res.set("+商品+");
}
}
}
class Consumer implements Runnable
{
private Resource res;
Consumer(Resource res)
{
this.res = res;
}
public void run()
{
while(true)
{
res.out();
}
}
}
public class NotifyDemo {
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();
}
}