多线程
1、线程类和实现多线程
进程:是一个正在执行中的程序。每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或者叫一个控制单元。
线程:程序中的控制单元,线程在控制着进程的执行。
一个进程至少有一个线程。
Java VM 启动的时候会有一个进程java.exe。存在主线程,这个线程运行的代码存在于main方法中。
1.1、继承Thread类
定义类继承Thread.
复写Thread类中的run方法。
创建实例调用线程的start方法,该方法作用:启动线程,调用run方法。
如:
public class TreadDemo {
//主线程
public static void main(String[] args) {
// TODO Auto-generated method stub
Thr1 t1 = new Thr1();
Thr2 t2 = new Thr2();//创建线程实例
t1.start();//调用start方法开启线程
t2.start();
int count = 1;
for(int x=1;x<70;x++)
System.out.println(Thread.currentThread().getName()+"..main...."+count++);
}
}
//线程1
class Thr1 extends Thread{
int count = 1;
public void run(){
for(int x=1;x<60;x++)
System.out.println(this.getName()+"...run1..."+count++);
}
}
//线程2
class Thr2 extends Thread{
int count = 1;
public void run(){
for(int y=1;y<60;y++)
System.out.println(this.getName()+"..run2....."+count++);
}
}
运行结果每次都不同
随机性
为什么要覆盖run方法呢?
Thread类用于描述线程。该类就定义了一个功能,用于存储线程要运行的代码。该存储功能就是run方法。
run和start方法.
状态图:
图 1-1
线程标识:名称:getName();线程拥有默认的名称:Thread-编号
void setName(String name) 改变线程名称,使之与参数 name 相同。
void setPriority(int newPriority) 更改线程的优先级。
Thread.currentThread()==this;获取当前线程。
sleep方法需要制定睡眠时间,单位是毫秒。一个特殊的状态:就绪。具备了执行资格,但是还没有获取资源。
static void yield() 暂停当前正在执行的线程对象,并执行其他线程。
void join() 调用该方法的线程需要执行完毕其他线程才会执行。
void interrupt() 束线程的冻结状态,使线程回到运行状态中来
1.2、实现Runnable接口。
class PrimeRun implements Runnable {
long minPrime;
PrimeRun(long minPrime) {
this.minPrime = minPrime;
}
public void run() {
// compute primes larger than minPrime
//. . .
}
}
然后,下列代码会创建并启动一个线程:
PrimeRun p = new PrimeRun(143);
new Thread(p).start();
1.3 两种方法的区别
继承Thread:线程代码存放在Thread子类run方法中。
实现Runnable:线程代码存在接口的子类的run方法。
实现Runnable接口比继承Thread类所具有的优势:
1):适合多个相同的程序代码的线程去处理同一个资源
2):可以避免java中的单继承的限制
3):增加程序的健壮性,代码可以被多个线程共享,代码和数据独立。
售票例子:
多窗口售票
无效线程异常
public class TicketDemo {
/**
* @param args
*/
public static void main(String[] args) {
Ticket tick = new Ticket();
Thread t1 = new Thread(tick);
Thread t2 = new Thread(tick);
Thread t3 = new Thread(tick);
Thread t4 = new Thread(tick);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
class Ticket implements Runnable{
private int tickNum = 10;
Object obj = new Object();
@Override
public void run() {
while(true){
synchronized(obj){
if(tickNum>0){
try{Thread.sleep(20);}catch(Exception e){}
System.out.println(Thread.currentThread().getName()+"..run.."+tickNum--);
}
}
}
}
}
2、多线程安全问题---同步
问题的原因:
当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,
另一个线程参与进来执行。导致共享数据的错误。
解决办法:
对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其他线程不可以参与执行。
同步代码块
synchronized(对象)
{
需要同步的代码
}
对象如同锁。持有锁的线程可以在同步中执行。没有持有锁的线程即使获取cpu的执行权,也进不去,因为没有获取锁。
共享数据
同步的前提:
1,必须要有两个或者两个以上的线程。
2,必须是多个线程使用同一个锁。
必须保证同步中只能有一个线程在运行。
好处:解决了多线程的安全问题。
弊端:多个线程需要判断锁,较为消耗资源,
同步函数
锁:this
同步静态函数
锁:类名.class
同步函数的锁是固定的this。
同步代码块的锁是任意的对象。
建议使用同步代码块。
单例设计模式
懒汉式
实例的延迟加载
class Single{
private Single(){}
private static Single s = null;
public static Single getInstance(){
if(s==null){
synchronized(Single.class){
if(s==null)
s=new Single();
}
}
return s;
}
}
典型死锁:
public class DeadLockDemo {
/**
* @param args
*/
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 MyLock{
//定义两把锁
static Object locka = new Object();
static Object lockb = new Object();
}
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");
}
}
}
}
}
}
3、线通信程间
存在安全问题,怎么解决这个问题呢?
等待唤醒机制
wait();
notify();
notifyAll();
为什么定义notifyAll,
因为需要唤醒对方线程。
因为只用notify,容易出现只唤醒本方线程的情况。导致程序中的所有线程都等待。
生产消费者
多个生产消费
while
notifyAll
public class ProCsuDemo {
/**
* @param args
*/
public static void main(String[] args) {
Resource res = new Resource();
Producer pro = new Producer(res);
Consumer con = new Consumer(res);
Thread t1 = new Thread(pro);
Thread t2 = new Thread(con);
Thread t3 = new Thread(pro);
Thread t4 = new Thread(con);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
class Resource{
private int count = 1;
private String name;
private boolean flag = false;
public synchronized void set(String name){
while(flag){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
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 (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"...消费者..."+this.name);
flag = false;
this.notifyAll();
}
}
class Producer implements Runnable{
private Resource res;
Producter(Resource res){
this.res = res;
}
@Override
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();
}
}
}
4、JDK1.5的新特性
java.util.concurrent.locks
Lock类
上锁
lock();
解锁
unlock();
Condition类
await();
signal();
signalAll();
class X {
private final Lock lock = new ReentrantLock();
// ...
public void m() {
lock.lock(); // block until condition holds
try {
// ... method body
} finally {
lock.unlock()
}
}
}
生成消费者
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ProCsuDemo2 {
/**
* @param args
*/
public static void main(String[] args) {
Resource2 res = new Resource2();
Producter2 pro = new Producter2(res);
Consumer2 con = new Consumer2(res);
Thread t1 = new Thread(pro);
Thread t2 = new Thread(con);
Thread t3 = new Thread(pro);
Thread t4 = new Thread(con);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
class Resource2{
private int count = 1;
private String name;
final Lock lock = new ReentrantLock();
final Condition con_pro = lock.newCondition();
final Condition con_csu = lock.newCondition();
private boolean flag = false;
public void set(String name){
lock.lock();
try {
while(flag){
con_pro.await();
}
this.name = name +"--"+ (count++);
System.out.println(Thread.currentThread().getName()+".....生产者..."+this.name);
flag = true;
con_csu.signal();
} catch (Exception e) {
e.printStackTrace();
}finally{
lock.unlock();
}
}
public void out(){
lock.lock();
try {
while(!flag){
con_csu.await();
}
System.out.println(Thread.currentThread().getName()+"...消费者..."+this.name);
flag = false;
con_pro.signal();
} catch (Exception e) {
e.printStackTrace();
}finally{
lock.unlock();
}
}
}
class Producter2 implements Runnable{
private Resource2 res;
Producter2(Resource2 res){
this.res = res;
}
@Override
public void run() {
while(true){
res.set("+商品+");
}
}
}
class Consumer2 implements Runnable{
private Resource2 res;
Consumer2(Resource2 res){
this.res = res;
}
public void run(){
while(true){
res.out();
}
}
}
停止线程。
stop方法过时了
控制run方法控制线程结束。
Thread类
interrupt();冻结状态的线程强制清除。
守护线程:
setDaemon(true);
----------------
join();
申请加入执行,要执行权,结束之后其他线程才能执行。
优先级有1-10个等级
setPriority();
默认优先级为5;
MAX_PRIORITY
MIN_PRIORITY
NORM_PRIROITY
yield()方法;
稍微减少线程执行频率,暂停正在执行的线程,并执行其他线程。
使用匿名内部类书写线程
Thread t = new Thread(new Runnable(){
public void run(){}
});
t.start();
停止线程:
1,stop方法。
2,run方法结束。
怎么控制线程的任务结束呢?
任务中都会有循环结构,只要控制住循环就可以结束任务。
控制循环通常就用定义标记来完成。
但是如果线程处于了冻结状态,无法读取标记。如何结束呢?
可以使用interrupt()方法将线程从冻结状态强制恢复到运行状态中来,让线程具备cpu的执行资格。
当时强制动作会发生了InterruptedException,记得要处理
5、线程池(重要)jdk1.5新特性
java.util.concurrent包提供了线程池的实现
图 5-1
图 5-2
------- android培训、java培训、java学习型技术博客、期待与您交流! ----------