黑马程序员 Java基础 多线程2

------ Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

一Lock

JDK5以后的针对线程的锁定操作和释放操作

Lock lock = new ReentrantLock()获得对象

lock.lock();   在操作数据的代码前加锁

lock.unlock(); 在操作数据的代码后释放锁

 

二 死锁问题

描述 

多线程环境中,出现了锁的嵌套,可能会发生死锁。

 

代码体现

public void run(){

if(flag){

synchronized(T02MyLock.objA){

System.out.println("if objA");

synchronized(T02MyLock.objB){

System.out.println("if objB");

}

}

}else{

synchronized(T02MyLock.objB){

System.out.println("else objB");

synchronized(T02MyLock.objA){

System.out.println("else objA");

}

}

}

}


此时,如果两个线程分别走 true false 两个分支,则有可能发生死锁

 

三 线程间通信问题(生产者和消费者多线程问题)

代码1

public class Student{

public String name;

public int age;

}

 

public class GetThread implements Runnable{

private Student s;

 

public GetThread(s){

this.s = s;

}

 

public void run(){

System.out.println(s.name + "  " + s.age);

}

}

 

public class SetThread implements Runnable{

private Student s;

 

public SetThread(s){

this.s = s;

}

 

public void run(){

s.name = "";

s.age = 27;

}

}

 

public class StudentDemo{

public static void main(String[] args) {

Student s = new Student();

 

SetThread st = new SetThread(s);

GetThread gt = new GetThread(s);

 

Thread t1 = new Thread(st);

Thread t2 = new Thread(gt);

 

t1.start();

t2.start();

}

}


资源类: Student

设置数据类:SetThread(生产者)

获取数据类:GetThread(消费者)

测试类:StudentDemo

 

具体描述:多线程环境下,生产和消费同时执行。处理相同的资源。在处理相同资源时需要同步,即线程间通信。

1)出现的问题1:

线程安全问题。

解决方案:可以加锁。

 

2)完善思路:

生产、消费是个不断的过程,所以可以在run函数里面,加上while()循环。(当然本例的实际意义不明显)

可以区分每次具体生产的不一样,所以可以在set函数里,(通过新增一个变量),来控制每次生产的不同种类的东西(对应的student,就是每次设置不同的名字)

 

3)出现的问题2:

可能会连续生产却没有消费,或者对同一个商品进行多次消费。(体现在本例中就是,同一个名字被不停的读出,而来不及设置另一个名字)

解决方案:等待唤醒机制。

 

四 等待唤醒机制(代码及理解)

代码2:

(是对代码1的改进。其中测试类没有变,所以没有贴出代码)

public class SetThread implements Runnable{

private Student s;

private int x = 0;

 

public SetThread(s){

this.s = s;

}

 

public void run(){

while(true){

if( x % 2 ){

s.set("林青霞", 27);

}else{

s.set("刘意", 30);

}

x++;

}

}

}

 

public class GetThread implements Runnable{

private Student s;

 

public GetThread(s){

this.s = s;

}

 

public void run(){

while(true){

s.get();

}

}

}

 

public class Student{

private String name;

private int age;

private boolean flag;

 

public synchronized void set(String name, int age){

if(flag){

try{

this.wait();

}catch(InterruptedException e){

e.printStackTrace();

}

}

this.name = name;

this.age = age;

 

flag = true;

this.notify();

}

 

public synchronized void get(){

if(!flag){

try{

this.wait();

}catch(InterruptedException e){

e.printStackTrace();

}

}

 

System.out.println(name + "  " + age);

 

flag = false;

this.notify();

}

}



 

wait()和notify(),为了确保set()和get()可以依次执行

1)这些方法必须要标示所属的锁

当A锁上的线程wait后,只能由A锁的notify唤醒

2)这三个方法都定义在Object中

由于锁可以是任意对象,那么能被任意对象调用的方法也应定义在Object中。

 

wait()和sleep()的区别

wait:可以指定时间也可以不指定时间。不指定时间时,只能由对应的notifynotifyAll唤醒。

sleep:必须指定时间,记满时间后,自动从冻结状态转成运行状态。(临时阻塞状态)

 

 

注:线程的状态转换图中,从运行 -> 就绪,是因为被别的夺取了执行权

 

 

五 其他

线程组

ThreadGroup:可以通过Thread的构造函数明确新线程对象所属的线程组。

(默认在main线程组中。)

线程组的好处,可以对多个同组线程,进行统一的操作。默认都属于main线程组。

 

线程池 

ExecutorService pool = Executors.newFixedThreadPool(2);  

 

// 这里传一个Runnable()的子类对象

pool.submit(my1);

pool.submit(my2);

 

pool.shutdown();


第一行的声明语句处,可以指定大小。

 

线程的匿名内部类

public static void main(String[] args) {

// 继承Thread类来实现多线程

new Thread(){

public void run(){

for(int i = 0; i < 10; i++){

System.out.println(Thread.currentThread().getName() + ":" + i);

}

}

}.start();

 

// 实现Runnable接口来实现多线程

new Thread(new Runnable(){

public void run(){

for(int i = 0; i < 10; i++){

System.out.println(Thread.currentThread().getName() + ":" + i);

}

}

}){}.start();

 

// 更有难度的

new Thread(new Runnable(){

public void run(){

for (int x = 0; x < 10; x++) {

System.out.println("hello" + ":" + x);

}

}

}){

public void run(){

for (int x = 0; x < 10; x++) {

System.out.println("world" + ":" + x);

}

}

}.start();

}


需要注意的是,第三种方式,最终是输出 world 的,而非 hello

 

 

六 单例设计模式

// 单例模式:保证类在内存中只有一个对象。

饿汉式

public class Student {

private Student(){}

private static Student s = new Student();

public static Student getStudent(){

return s;

}

}


一开始就给成员变量赋值(或者说类一加载就创建对象)

 

懒汉式

public class Teacher {

private Teacher(){}

private static Teacher t;

public synchronized static Teacher getTeacher(){

if( t == null ){

t = new Teacher();

}

return t;

}

}


用的时候,才去创建对象

存在的问题:

多线程环境中,共享数据,多条操作语句,所以会有线程安全问题

所以在上例中,加了synchronized

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值