黑马程序员多线程视频总结

线程池的工作模型主要两部分组成,一部分是运行Runnable的Thread对象,另一部分就是阻塞队列。

由线程池创建的Thread对象其内部的run方法会通过阻塞队列的take方法获取一个Runnable对象,然后执行这个Runnable对象的run方法(即,在Thread的run方法中调用Runnable对象的run方法)。当Runnable对象的run方法执行完毕以后,Thread中的run方法又循环的从阻塞队列中获取下一个Runnable对象继续执行。这样就实现了Thread对象的重复利用,也就减少了创建线程和销毁线程所消耗的资源。

当需要向线程池提交任务时会调用阻塞队列的offer方法向队列的尾部添加任务。提交的任务实际上就是是Runnable对象或Callable对象。

1.线程范围共享变量

public class ThreadScopeShareData {

private static int data = 0;
private static Map<Thread, Integer> threadData = new HashMap<Thread, Integer>();
public static void main(String[] args) {
    for(int i=0;i<2;i++){
        new Thread(new Runnable(){
            @Override
            public void run() {
                int data = new Random().nextInt();
                System.out.println(Thread.currentThread().getName() 
                        + " has put data :" + data);
                //threadData.put(Thread.currentThread(), data);
                threadData.set(data);//这样写即可
                new A().get();
                new B().get();
            }
        }).start();
    }
}

static class A{
    public void get(){
        int data = threadData.get(Thread.currentThread());
        System.out.println("A from " + Thread.currentThread().getName() 
                + " get data :" + data);
    }
}

static class B{
    public void get(){
        int data = threadData.get(Thread.currentThread());          
        System.out.println("B from " + Thread.currentThread().getName() 
                + " get data :" + data);
    }       
}

}

2.TreadLocal实现线程范围共享变量

public class ThreadLocalTest {
//一个TreadLocal只能代表一个变量,要是有多个数据需要在线程范围共享就要有多个TreadLocal,或者弄成类
private static ThreadLocal x = new ThreadLocal();
private static ThreadLocal myThreadScopeData = new ThreadLocal();
public static void main(String[] args) {
for(int i=0;i<2;i++){
new Thread(new Runnable(){
@Override
public void run() {
int data = new Random().nextInt();
System.out.println(Thread.currentThread().getName()
+ ” has put data :” + data);
x.set(data);

                /*MyThreadScopeData myData = new MyThreadScopeData();
                myData.setName("name" + data);
                myData.setAge(data);
                myThreadScopeData.set(myData);*/

                MyThreadScopeData.getThreadInstance().setName("name" + data);
                MyThreadScopeData.getThreadInstance().setAge(data);
                new A().get();
                new B().get();
            }
        }).start();
    }
}

static class A{
    public void get(){
        int data = x.get();
        System.out.println("A from " + Thread.currentThread().getName() 
                + " get data :" + data);

        /*MyThreadScopeData myData = myThreadScopeData.get();;
        System.out.println("A from " + Thread.currentThread().getName() 
                + " getMyData: " + myData.getName() + "," +
                myData.getAge());*/

        MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();
        System.out.println("A from " + Thread.currentThread().getName() 
                + " getMyData: " + myData.getName() + "," +
                myData.getAge());
    }
}

static class B{
    public void get(){
        int data = x.get();         
        System.out.println("B from " + Thread.currentThread().getName() 
                + " get data :" + data);
        //得到当前线程的对象
        MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();
        System.out.println("B from " + Thread.currentThread().getName() 
                + " getMyData: " + myData.getName() + "," +
                myData.getAge());           
    }       
}

}

class MyThreadScopeData{
//按照单例相似的去写优雅的方式
private MyThreadScopeData(){}
//不用synchronized因为一个线程对应修改get set自己的变量
public static /synchronized/ MyThreadScopeData getThreadInstance(){
MyThreadScopeData instance = map.get();
if(instance == null){
instance = new MyThreadScopeData();
map.set(instance);
}
return instance;
}
//private static MyThreadScopeData instance = null;//new MyThreadScopeData();
private static ThreadLocal map = new ThreadLocal();

private String name;
private int age;
public String getName() {
    return name;
}
public void setName(String name) {
    this.name = name;
}
public int getAge() {
    return age;
}
public void setAge(int age) {
    this.age = age;
}

}

3.多线程访问共享对象和数据的方法
如果每个线程执行的代码相同,可用同一个Runnable对象,Runnable中由共享数据(例如卖票)
如果每个线程执行的代码不同,可将共享数据封装在另一个对象中,然后将这个对象逐一传递给各Runnable

public class MultiThreadShareData {

private static ShareData1 data1 = new ShareData1();

public static void main(String[] args) {
    ShareData1 data2 = new ShareData1();
    new Thread(new MyRunnable1(data2)).start();
    new Thread(new MyRunnable2(data2)).start();

    final ShareData1 data1 = new ShareData1();
    new Thread(new Runnable(){
        @Ov  erride
        public void run() {
            data1.decrement();

        }
    }).start();
    new Thread(new Runnable(){
        @Override
        public void run() {
            data1.increment();

        }
    }).start();

}

}

class MyRunnable1 implements Runnable{
    private ShareData1 data1;
    public MyRunnable1(ShareData1 data1){
        this.data1 = data1;
    }
    public void run() {
        data1.decrement();

    }
}

class MyRunnable2 implements Runnable{
    private ShareData1 data1;
    public MyRunnable2(ShareData1 data1){
        this.data1 = data1;
    }
    public void run() {
        data1.increment();
    }
}

class ShareData1 /*implements Runnable*/{

/* private int count = 100;
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
count–;
}
}*/

    private int j = 0;
    public synchronized void increment(){
        j++;
    }

    public synchronized void decrement(){
        j--;
    }
}

java5之后:
4.原子类:AtomicInteger AtomicIntegerArray 。。。应用于多线程共享的数据

5.tomcat服务器中
new Thread(){
while(池子中还有线程需要接待){
和线程聊一会;
}
}.start();

线程池
public class ThreadPoolTest {

public static void main(String[] args) {
    //ExecutorService threadPool = Executors.newFixedThreadPool(3); 固定数目的线程池,3个3个抢占资源
    //ExecutorService threadPool = Executors.newCachedThreadPool(); 数目动态变化的线程池,来多少线程池多大
    ExecutorService threadPool = Executors.newSingleThreadExecutor();单一线程池,如何实现线程死了后重新启动,当一个线程死了后,会马上找一个替补的线程
    for(int i=1;i<=10;i++){
        final int task = i;
        threadPool.execute(new Runnable(){
            @Override
            public void run() {
                for(int j=1;j<=10;j++){
                    try {
                        Thread.sleep(20);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + " is looping of " + j + " for  task of " + task);
                }
            }
        });
    }
    System.out.println("all of 10 tasks have committed! ");
    //threadPool.shutdownNow();

    //定时器
    Executors.newScheduledThreadPool(3).scheduleAtFixedRate(
            new Runnable(){
                @Override
            public void run() {
                System.out.println("bombing!");

            }},
            6,
            2,
            TimeUnit.SECONDS);
}

}

6.
public class CallableAndFuture {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newSingleThreadExecutor();
Future future =
threadPool.submit( ——提交一个返回值
new Callable() {
public String call() throws Exception {
Thread.sleep(2000);
return “hello”;
};
}
);
System.out.println(“等待结果”);
try {
System.out.println(“拿到结果:” + future.get());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

    //CompletionService用于提交一组Callable任务,take方法返回已完成的Callable任务对应的furtuer对象
    ExecutorService threadPool2 =  Executors.newFixedThreadPool(10);
    CompletionService<Integer> completionService = new ExecutorCompletionService<Integer>(threadPool2);
    //提交10个任务
    for(int i=1;i<=10;i++){
        final int seq = i;
        completionService.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                Thread.sleep(new Random().nextInt(5000));
                return seq;
            }
        });
    }
    //拿到10个结果
    for(int i=0;i<10;i++){
        try {
            System.out.println(
                    completionService.take().get());
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ExecutionException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

}

7.读写锁:读写互斥,写写互斥,读读没事
锁比synchronized更加面向对象,必须要再结尾finnal中释放锁

public class ReadWriteLockTest {
public static void main(String[] args) {
final Queue3 q3 = new Queue3();
for(int i=0;i<3;i++)
{
new Thread(){
public void run(){
while(true){
q3.get();
}
}

        }.start();

        new Thread(){
            public void run(){
                while(true){
                    q3.put(new Random().nextInt(10000));
                }
            }           

        }.start();
    }

}

}

class Queue3{
private Object data = null;//共享数据,只能有一个线程能写该数据,但可以有多个线程同时读该数据。
ReadWriteLock rwl = new ReentrantReadWriteLock();
public void get(){
rwl.readLock().lock();
try {
System.out.println(Thread.currentThread().getName() + ” be ready to read data!”);
Thread.sleep((long)(Math.random()*1000));
System.out.println(Thread.currentThread().getName() + “have read data :” + data);
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
rwl.readLock().unlock();
}
}

public void put(Object data){

    rwl.writeLock().lock();
    try {
        System.out.println(Thread.currentThread().getName() + " be ready to write data!");                  
        Thread.sleep((long)(Math.random()*1000));
        this.data = data;       
        System.out.println(Thread.currentThread().getName() + " have write data: " + data);                 
    } catch (InterruptedException e) {
        e.printStackTrace();
    }finally{
        rwl.writeLock().unlock();
    }


}

}

8.模拟缓存
这样写读写效率高
public class CacheDemo {
//内部定义一个map
private Map

黑马程序员多线程练习题主要包括两个问题。第一个问题是如何控制四个线程在打印log之前能够同时开始等待1秒钟。一种解决思路是在线程的run方法中调用parseLog方法,并使用Thread.sleep方法让线程等待1秒钟。另一种解决思路是使用线程池,将线程数量固定为4个,并将每个调用parseLog方法的语句封装为一个Runnable对象,然后提交到线程池中。这样可以实现一秒钟打印4行日志,4秒钟打印16条日志的需求。 第二个问题是如何修改代码,使得几个线程调用TestDo.doSome(key, value)方法时,如果传递进去的key相等(equals比较为true),则这几个线程应互斥排队输出结果。一种解决方法是使用synchronized关键字来实现线程的互斥排队输出。通过给TestDo.doSome方法添加synchronized关键字,可以确保同一时间只有一个线程能够执行该方法,从而实现线程的互斥输出。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [黑马程序员——多线程10:多线程相关练习](https://blog.csdn.net/axr1985lazy/article/details/48186039)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值