标签:
1 多线程概述
进程:正在进行中的程序
线程:就是进程中一个负责程序执行的控制单元(执行路径)
一个进程中可以多执行路径,称为多线程
一个进程中至少要有一个线程
开启多个线程是为了同时运行多部分代码
每一个线程都有自己运行的内容,这个内容可以称为线程要执行的任务。
2多线程创建的方式一
创建线程的目的是为了开启一条执行路径,去运行指定的代码和其它代码实现同时运行
而运行的指定代码就是这个执行路径的任务
java创建的主线程的任务都定义在主函数中
而自定义的线程的任务在哪里呢?
Thread类用于描述线程,线程是需要任务的 所以Thread类是对任务的描述
这个任务通过Thread类的run方法来体现。也就是说,run方法就是封装自定义线程运行任务的函数。
run方法中定义的就是线程要运行的任务代码
开启线程是为了运行指定代码,所以只有要继承Thread类,并复写run方法
将任务写在run方法中
/*
* 如何创建一个线程呢
*
* 创建线程方式一:继承Thread类
*
* 步骤:
* 1 定义一个类继承Thread类
* 2 覆盖Thread类中的run方法
* 3 直接创建Thread的子类对象创建线程
* 4 调用start方法开启线程并调用线程任务的run方法
*
*
* Thread类的getName是获取线程名称
* Thread类的current.getName()是获取当前运行的线程名称
* 创建线程时 可以通过构造函数为线程赋予自己的名称
*
*/
class Task extends Thread
{
public void run() {
for(int x=1;x<100;x++)
{
System.out.println(Thread.currentThread().getName()+"数字是"+x+getName());
}
}
}
public class ThreadTaskDemo {
public static void main(String[] args) {
Task a=new Task();
Task b=new Task();
a.start();
b.start();
for(int x=1;x<100;x++)
{
System.out.println(Thread.currentThread().getName()+"数字是"+x);
}
}
}
2 线程的状态
被创建 start()
运行 具备CPU的执行权
冻结 sleep(time) wait() notify() 释放执行权的同时释放执行资格
消亡 stop() run方法结束
临时阻塞 具备执行资格,正在等待执行权
cpu的执行资格:可以被CPU处理,在处理队列中排队
cpu的执行权:正在被CPU处理
3创建线程方式二 实现Runnable接口
/*
*
* 实现接口的方式创建线程
*/
public class ThreadDemo2 implements Runnable{
public void run() {
for(int x=1;x<100;x++)
{
System.out.println(Thread.currentThread().getName()+"数字是"+x);
}
}
public static void main(String[] args) {
Thread t1=new Thread(new ThreadDemo2());
Thread t2=new Thread(new ThreadDemo2());
t1.start();
t2.start();
for(int x=1;x<100;x++)
{
System.out.println(Thread.currentThread().getName()+"数字是"+x);
}
}
}
4 第二种方式创建线程的好处
1 将线程的任务从线程的子类中分离出来,进行单独的封装
按照面向对象的思想将任务封装成对象
2 避免了java单独继承的局限性
所以这种方式更加常用
5线程中的安全问题
当多条执行路径共享一个变量时,就会发生不同步的情况
/*
* 需求:卖票
*
*/
class TicketSale implements Runnable
{
private int piao=100;
public void salePiao() throws InterruptedException
{
while(true)
{
if(piao>0)
{
Thread.sleep(500);
System.out.println(piao--+":"+Thread.currentThread().getName());
}
}
}
public void run()
{
try {
salePiao();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class TicketDemo
{
public static void main(String[] args) {
TicketSale task=new TicketSale();
Thread t1=new Thread(task);
Thread t2=new Thread(task);
Thread t3=new Thread(task);
Thread t4=new Thread(task);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
6解决不同步
就需要用同步代码块来解决
/*
* 需求:卖票
*
*/
class TicketSale implements Runnable
{
private int piao=100;
Object obj=new Object();
public void salePiao() throws InterruptedException
{
synchronized (obj)
{
while(true)
{
if(piao>0)
{
Thread.sleep(500);
System.out.println(piao--+":"+Thread.currentThread().getName());
}
}
}
}
public void run()
{
try {
salePiao();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class TicketDemo
{
public static void main(String[] args) {
TicketSale task=new TicketSale();
Thread t1=new Thread(task);
Thread t2=new Thread(task);
Thread t3=new Thread(task);
Thread t4=new Thread(task);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
7 同步的优点和弊端
优点:解决了不同步的问题
缺点:要判断锁,效率低下
要学会使用同步 否则乱使用同步会导致很多的问题出现 而且要学会判断哪里需要同步 哪里不需要同步
8同步函数的锁 (this指针)
9静态函数的锁(该函数所在的类的字节码对象)
10懒汉式涉及的多线程问题
class Single
{
private static Single s=null;
private Single(){}
public static Single getInstance()
{
if(s==null)
{
synchronized (Single.class)
{
if(s==null)
s=new Single();
}
}
return s;
}
}
public class Demo {
}
11 死锁示例
class Task implements Runnable
{
private boolean flag;
public Task(boolean flag)
{
this.flag=flag;
}
public void run()
{
if(flag)
{
while(true)
{
synchronized (Lock.locka)
{
System.out.println("if locka");
synchronized (Lock.lockb)
{
System.out.println("if lockb");
}
}
}
}
else
{
while(true)
{
synchronized (Lock.lockb)
{
System.out.println("else lockb");
synchronized (Lock.locka)
{
System.out.println("else locka");
}
}
}
}
}
}
class Lock
{
static Object locka=new Object();
static Object lockb=new Object();
}
public class Demo
{
public static void main(String[] args) {
Task task1=new Task(true);
Task task2=new Task(false);
Thread t1=new Thread(task1);
Thread t2=new Thread(task2);
t1.start();
t2.start();
}
}
12 线程间的通信
class Resource
{
String name;
String sex;
}
class Input implements Runnable
{
Resource r;
Input(Resource r)
{
this.r=r;
}
public void run()
{
int x=0;
while(true)
{
synchronized(r)
{
if(x==0)
{
r.name="君临";
r.sex="男";
}
else
{
r.name="大猪";
r.sex="男";
}
x=(x+1)%2;
}
}
}
}
class Output implements Runnable
{
Resource r;
Output(Resource r)
{
this.r=r;
}
public void run()
{
while(true)
{
synchronized (r)
{
System.out.println("姓名"+r.name+"...."+"性别"+r.sex);
}
}
}
}
public class Demo
{
public static void main(String[] args) {
Resource r=new Resource();
Input in=new Input(r);
Output out=new Output(r);
Thread t1=new Thread(in);
Thread t2=new Thread(out);
t1.start();
t2.start();
}
}
如何使上述的程序可以交替输出呢?
就需要使用等待唤醒机制。
13 等待唤醒机制
/* 等待/唤醒机制
*
* 涉及的方法
*
* 1 wait 让线程处于冻结状态,被wait的线程会 被存储到线程池中
* 2 notify 随机叫醒线程池中的一个线程
* 3 notifyAll 叫醒线程池中的所有线程
*
* 这些方法都必须定义在同步中
*
* 因为这些方法是用于操作线程状态的方法
* 必须要明确到底操作的是哪个锁上的线程
*/
class Resource
{
String name;
String sex;
boolean flag=false;
}
class Input implements Runnable
{
Resource r;
Input(Resource r)
{
this.r=r;
}
public void run()
{
int x=0;
while(true)
{
synchronized(r)
{
if(r.flag)
try
{
r.wait();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
if(x==0)
{
r.name="君临";
r.sex="男";
}
else
{
r.name="大猪";
r.sex="男";
}
r.flag=true;
r.notify();
x=(x+1)%2;
}
}
}
}
class Output implements Runnable
{
Resource r;
Output(Resource r)
{
this.r=r;
}
public void run()
{
while(true)
{
synchronized (r)
{
if(!r.flag)
{
try {
r.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else
{
System.out.println("姓名"+r.name+"...."+"性别"+r.sex);
r.flag=false;
r.notify();
}
}
}
}
}
public class Demo
{
public static void main(String[] args) {
Resource r=new Resource();
Input in=new Input(r);
Output out=new Output(r);
Thread t1=new Thread(in);
Thread t2=new Thread(out);
t1.start();
t2.start();
}
}
这个代码是可以优化的
14 生产者消费者问题
/* 等待/唤醒机制
*
* 涉及的方法
*
* 1 wait 让线程处于冻结状态,被wait的线程会 被存储到线程池中
* 2 notify 随机叫醒线程池中的一个线程
* 3 notifyAll 叫醒线程池中的所有线程
*
* 这些方法都必须定义在同步中
*
* 因为这些方法是用于操作线程状态的方法
* 必须要明确到底操作的是哪个锁上的线程
*/
class Resource
{
String name;
String sex;
private int count=1;
boolean flag=false;
public synchronized void set(String name)
{ if(flag)
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.name=name+count;
count++;
System.out.println(Thread.currentThread().getName()+"....生产者......"+this.name);
flag=true;
this.notify();
}
public synchronized void out()
{
if(!flag)
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"....消费者..。。。。。...."+this.name);
flag=false;
this.notify();
}
}
class Product implements Runnable
{
Resource r;
Product (Resource r)
{
this.r=r;
}
public void run()
{
while(true)
{
r.set("北京烤鸭");
}
}
}
class Consumer implements Runnable
{
Resource r;
Consumer(Resource r)
{
this.r=r;
}
public void run()
{
while(true)
{
r.out();
}
}
}
public class Demo
{
public static void main(String[] args) {
Resource r=new Resource();
Product p=new Product(r);
Consumer c=new Consumer(r);
Thread t1=new Thread(p);
//Thread t2=new Thread(p);
// Thread t3=new Thread(c);
Thread t4=new Thread(c);
t1.start();
//t2.start();
//t3.start();
t4.start();
}
}
如果是一个消费者 一个生产者 这个程序是可以交替的
但如果是多消费者 多消费者 就会出现问题
/* 等待/唤醒机制
*
* 涉及的方法
*
* 1 wait 让线程处于冻结状态,被wait的线程会 被存储到线程池中
* 2 notify 随机叫醒线程池中的一个线程
* 3 notifyAll 叫醒线程池中的所有线程
*
* 这些方法都必须定义在同步中
*
* 因为这些方法是用于操作线程状态的方法
* 必须要明确到底操作的是哪个锁上的线程
*/
class Resource
{
String name;
String sex;
private int count=1;
boolean flag=false;
public synchronized void set(String name)
{ if(flag)
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.name=name+count;
count++;
System.out.println(Thread.currentThread().getName()+"....生产者......"+this.name);
flag=true;
this.notify();
}
public synchronized void out()
{
if(!flag)
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"....消费者..。。。。。...."+this.name);
flag=false;
this.notify();
}
}
class Product implements Runnable
{
Resource r;
Product (Resource r)
{
this.r=r;
}
public void run()
{
while(true)
{
r.set("北京烤鸭");
}
}
}
class Consumer implements Runnable
{
Resource r;
Consumer(Resource r)
{
this.r=r;
}
public void run()
{
while(true)
{
r.out();
}
}
}
public class Demo
{
public static void main(String[] args) {
Resource r=new Resource();
Product p=new Product(r);
Consumer c=new Consumer(r);
Thread t1=new Thread(p);
Thread t2=new Thread(p);
Thread t3=new Thread(c);
Thread t4=new Thread(c);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
此时可以考虑将if 改成 while (当程序恢复运行状态,重新判断标志位),此时会发生死锁。 程序都冻结了 这时候应该使用notifyAll()
/* 等待/唤醒机制
*
* 涉及的方法
*
* 1 wait 让线程处于冻结状态,被wait的线程会 被存储到线程池中
* 2 notify 随机叫醒线程池中的一个线程
* 3 notifyAll 叫醒线程池中的所有线程
*
* 这些方法都必须定义在同步中
*
* 因为这些方法是用于操作线程状态的方法
* 必须要明确到底操作的是哪个锁上的线程
*/
class Resource
{
String name;
String sex;
private int count=1;
boolean flag=false;
public synchronized void set(String name)
{ while(flag)
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.name=name+count;
count++;
System.out.println(Thread.currentThread().getName()+"....生产者......"+this.name);
flag=true;
this.notifyAll();
}
public synchronized void out()
{
while(!flag)
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"....消费者..。。。。。...."+this.name);
flag=false;
this.notifyAll();
}
}
class Product implements Runnable
{
Resource r;
Product (Resource r)
{
this.r=r;
}
public void run()
{
while(true)
{
r.set("北京烤鸭");
}
}
}
class Consumer implements Runnable
{
Resource r;
Consumer(Resource r)
{
this.r=r;
}
public void run()
{
while(true)
{
r.out();
}
}
}
public class Demo
{
public static void main(String[] args) {
Resource r=new Resource();
Product p=new Product(r);
Consumer c=new Consumer(r);
Thread t1=new Thread(p);
Thread t2=new Thread(p);
Thread t3=new Thread(c);
Thread t4=new Thread(c);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
总结
if判断标记,只有一次,会导致不该运行的线程运行了,出现数据错误
While判断标记 解决了线程获取执行权后,是否要运行
Notify 只能唤醒一个线程,如果本方唤醒本方 没有意义,而且while 判断标记+Notify会导致死锁
notifyAll 可以唤醒对方线程 解决了问题
15 JDK5.0新特性
以前的同步是隐式操作,JDK5.0新特性是将同步和锁封装成了对象,进行显示操作。同时,可以创建多个监视器,不再使用wait和notify而是await和signal
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class Resource
{
String name;
String sex;
private int count=1;
boolean flag=false;
Lock lock=new ReentrantLock();
Condition con=lock.newCondition();
public void set(String name)
{
lock.lock();
try
{
while(flag)
{
try { con.await();} catch (InterruptedException e) {e.printStackTrace();}
}
this.name=name+count;
count++;
System.out.println(Thread.currentThread().getName()+"....生产者......"+this.name);
flag=true;
con.signalAll();
}
finally
{
lock.unlock();
}
}
public void out()
{
lock.lock();
try
{
while(!flag)
try {con.await();} catch (InterruptedException e) {e.printStackTrace();}
System.out.println(Thread.currentThread().getName()+"....消费者..。。。。。...."+this.name);
flag=false;
con.signalAll();
}
finally
{
lock.unlock();
}
}
}
class Product implements Runnable
{
Resource r;
Product (Resource r)
{
this.r=r;
}
public void run()
{
while(true)
{
r.set("北京烤鸭");
}
}
}
class Consumer implements Runnable
{
Resource r;
Consumer(Resource r)
{
this.r=r;
}
public void run()
{
while(true)
{
r.out();
}
}
}
public class Demo
{
public static void main(String[] args) {
Resource r=new Resource();
Product p=new Product(r);
Consumer c=new Consumer(r);
Thread t1=new Thread(p);
Thread t2=new Thread(p);
Thread t3=new Thread(c);
Thread t4=new Thread(c);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
只是表示形式变化 思想还是一样的
要注意wait方法和notify方法是通过监视器来实现的
既然能创建多个监视器对象 那么就可以选择只唤醒对方线程
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class Resource
{
String name;
String sex;
private int count=1;
boolean flag=false;
Lock lock=new ReentrantLock();
Condition pro_con=lock.newCondition();
Condition con_con=lock.newCondition();
public void set(String name)
{
lock.lock();
try
{
while(flag)
{
try { pro_con.await();} catch (InterruptedException e) {e.printStackTrace();}
}
this.name=name+count;
count++;
System.out.println(Thread.currentThread().getName()+"....生产者......"+this.name);
flag=true;
con_con.signalAll();
}
finally
{
lock.unlock();
}
}
public void out()
{
lock.lock();
try
{
while(!flag)
try {con_con.await();} catch (InterruptedException e) {e.printStackTrace();}
System.out.println(Thread.currentThread().getName()+"....消费者..。。。。。...."+this.name);
flag=false;
pro_con.signalAll();
}
finally
{
lock.unlock();
}
}
}
class Product implements Runnable
{
Resource r;
Product (Resource r)
{
this.r=r;
}
public void run()
{
while(true)
{
r.set("北京烤鸭");
}
}
}
class Consumer implements Runnable
{
Resource r;
Consumer(Resource r)
{
this.r=r;
}
public void run()
{
while(true)
{
r.out();
}
}
}
public class Demo
{
public static void main(String[] args) {
Resource r=new Resource();
Product p=new Product(r);
Consumer c=new Consumer(r);
Thread t1=new Thread(p);
Thread t2=new Thread(p);
Thread t3=new Thread(c);
Thread t4=new Thread(c);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
这样可以提高效率
16
sleep和wait的区别
Sleep 释放执行资格 不释放锁
Wait 释放执行资格 释放锁
在同步中,可能出现多个线程,但是还是会遵循谁拿到锁,谁先运行的原则。
17 结束线程的方法
1 使用标志位
但是如果线程处于冻结状态,无法获取标志位时,就需要使用interrupt方法来破除冻结状态 此时会抛出异常 需要处理
2 run方法结束
18守护线程
setDeamon()
Thread t2=new Thread();
T2.setDeamon();
如果将一个线程 设置为守护线程,那么它就将成为后台线程,当所有前台线程结束时,这个后台线程无论出于何种状态,也会结束。
19join方法
在A线程中 如果运行到了 B线程.join()这个方法,那么A线程会等到B线程运行完后才运行 也会抛出异常 需要处理
20 线程优先级
一般为
1 MIN_PRIORITY
5 NORM_PRIORITY
10 MAX_PRIORITY 三个优先级
优先级越高,获取CPU执行权的几率越大。
21 yield
Thread.yield()
如果某线程运行到这个方法,那么这个线程会立即释放执行权。
标签:
原文地址:http://www.cnblogs.com/HJL085/p/5825423.html