多线程
1.创建线程的方式● 继承Thread。
● 实现Runnable的接口。
2.线程安全问题
当多条语句在操作同一线程共享数据时,一个线程对多条语句只执行了一部分,还没用执行完,另一个线程参与进来执行。导致共享数据的错误。
解决办法:对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其他线程不可以参与执行。
使用同步Synchronized:
synchronized(对象)
{
需要被同步的代码
}
示例:多个窗口同事卖票。
package it.practise.com.thread;
public 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 tickets = 100;
Object obj = new Object();
public void run() {
while(true) {
synchronized(obj) {
if(tickets > 0) {
System.out.println(Thread.currentThread().getName() + "::" + tickets--);
}
}
}
}
}
3.生产者消费问题
JDK1.5中提供了多线程升级解决方案。将Synchronized替换成显式的Lock操作。
将Object中的wait, notify, notifyAll,替换成了Condition对象。该对象可以通过Lock获取。
package it.practise.com.thread;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ProducerConsumerDemo {
<span style="white-space:pre"> </span>public static void main(String[] args) {
<span style="white-space:pre"> </span>Resource r = new Resource();
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>Producer pro = new Producer(r);
<span style="white-space:pre"> </span>Consumer con = new Consumer(r);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>Thread t1 = new Thread(pro);
<span style="white-space:pre"> </span>Thread t2 = new Thread(pro);
<span style="white-space:pre"> </span>Thread t3 = new Thread(con);
<span style="white-space:pre"> </span>Thread t4 = new Thread(con);
<span style="white-space:pre"> </span>t1.start();
<span style="white-space:pre"> </span>t2.start();
<span style="white-space:pre"> </span>t3.start();
<span style="white-space:pre"> </span>t4.start();
<span style="white-space:pre"> </span>}
}
class Resource {
<span style="white-space:pre"> </span>private String name;
<span style="white-space:pre"> </span>private int count = 1;
<span style="white-space:pre"> </span>private boolean flag = false;
<span style="white-space:pre"> </span>private Lock lock = new ReentrantLock();
<span style="white-space:pre"> </span>Condition cp = lock.newCondition();
<span style="white-space:pre"> </span>Condition cc = lock.newCondition();
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>public void set(String name) throws InterruptedException {
<span style="white-space:pre"> </span>lock.lock();
<span style="white-space:pre"> </span>try{
<span style="white-space:pre"> </span>while(flag)
<span style="white-space:pre"> </span>cp.await();
<span style="white-space:pre"> </span>this.name = name + "--" + count++;
<span style="white-space:pre"> </span>System.out.println(Thread.currentThread().getName() + "...生产者..." + this.name);
<span style="white-space:pre"> </span>flag = true;
<span style="white-space:pre"> </span>cc.signal();
<span style="white-space:pre"> </span>} finally {
<span style="white-space:pre"> </span>lock.unlock();
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>public synchronized void out() throws InterruptedException {
<span style="white-space:pre"> </span>lock.lock();
<span style="white-space:pre"> </span>try{
<span style="white-space:pre"> </span>while(!flag)
<span style="white-space:pre"> </span>cc.await();
<span style="white-space:pre"> </span>System.out.println(Thread.currentThread().getName() + "*******消费者*******" + this.name);
<span style="white-space:pre"> </span>flag = false;
<span style="white-space:pre"> </span>cp.signal();
<span style="white-space:pre"> </span>} finally {
<span style="white-space:pre"> </span>lock.unlock();
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
}
class Producer implements Runnable {
<span style="white-space:pre"> </span>Resource r = new Resource();
<span style="white-space:pre"> </span>Producer(Resource r) {
<span style="white-space:pre"> </span>this.r = r;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>public void run() {
<span style="white-space:pre"> </span>while(true) {
<span style="white-space:pre"> </span>try {
<span style="white-space:pre"> </span>r.set("商品");
<span style="white-space:pre"> </span>} catch (InterruptedException e) {
<span style="white-space:pre"> </span>e.printStackTrace();
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}
}
class Consumer implements Runnable {
<span style="white-space:pre"> </span>Resource r = new Resource();
<span style="white-space:pre"> </span>Consumer(Resource r) {
<span style="white-space:pre"> </span>this.r = r;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>public void run() {
<span style="white-space:pre"> </span>while(true) {
<span style="white-space:pre"> </span>try {
<span style="white-space:pre"> </span>r.out();
<span style="white-space:pre"> </span>} catch (InterruptedException e) {
<span style="white-space:pre"> </span>e.printStackTrace();
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}
}
4.线程停止
stop方法已经过时,如何停止线程呢?
只有一种,run方法结束。
开启多线程,通常都是循环结构,只要控制住循环,run方法就可以结束,也就是线程结束。
5.特殊情况:
当线程处于了冻结状态,就不会读取到标记,那么线程就不会结束。
当没有指定的方式让冻结的线程恢复运行状态时,这时需要对冻结进行清除,强制让线程恢复运行状态,这样就可以操作标记,让线程结束。
Thread类提供了该方法 interrupt()
守护线程
void setDaemon(boolean on) 将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。该方法必须在启动线程前调用。
Join方法:
调用该方法的线程会抢夺执行权,其他线程会冻结,直到该线程结束后才会恢复到运行状态。
优先级&yield方法:
优先级一共10级,10最高,默认是5。
yield():暂停当前正在执行的线程对象,并执行其他线程。