• java多线程总结


    线程状态

    • Runnable
    • Blocked
      sleep、join、wait、synchronized 四个关键字都会使线程进入Blocked状态
    • Running
    • Dead

    synchronized关键字

    • Object类有两个监视器相关的方法wait、notify
    • synchronized和wait、notify同时使用,wait、notify必须在synchronized中
    • synchronized(obj)同步代码块使用obj对象的监视器实现同步
    • 实例方法使用synchronized锁定的是当前实例
    • 静态方法使用synchronized锁定的是当前类的所有实例

    synchronized关键字实现多线程同步

    public class TestSynchronized {
    	public static void main(String[] args) throws InterruptedException {
    		Test test = new Test();
    		List<Thread> listThread = new ArrayList<>();
    		for (int i = 0; i < 100; i++) {
    			Thread thread = new Thread(new Runnable() {
    				@Override
    				public void run() {
    					for (int j = 0; j < 100; j++) {
    						test.Increase();
    					}
    				}
    			});
    			listThread.add(thread);
    			thread.start();
    		}
    		// 主线程等待所有子线程执行完成
    		for (Thread t : listThread) {
    			t.join();
    		}
    		test.print();
    	}
    }
    class Test {
    	int i = 0;
    
    	public synchronized void Increase() {
    		i++;
    	}
    	public void print() {
    		System.out.println(i);
    	}
    }
    

    synchronized配合wait、notify实现生产者消费者

    public class ProducerConsumer {
    
    	public static void main(String[] args) {
    		ProCon proCon = new ProCon();
    		
    		//生产者
    		new Thread(new Runnable() {
    			@Override
    			public void run() {
    				try {
    					for (int i = 0; i < 20; i++) {
    						proCon.pro(i);
    						Thread.sleep(1000);
    					}
    				} catch (InterruptedException e) {
    				}
    			}
    		}).start();
    		
    		//消费者1
    		new Thread(new Runnable() {
    			@Override
    			public void run() {
    				try {
    					while (true) {
    						proCon.con();
    						Thread.sleep(3000);
    					}
    				} catch (InterruptedException e) {
    				}
    			}
    		}).start();
    
    		//消费者2
    		new Thread(new Runnable() {
    			@Override
    			public void run() {
    				try {
    					while (true) {
    						proCon.con();
    						Thread.sleep(3000);
    					}
    				} catch (InterruptedException e) {
    				}
    			}
    		}).start();
    	}
    
    }
    
    class ProCon {
    	List<Integer> listProduct = new ArrayList<Integer>();
    
    	public synchronized void pro(int pro) throws InterruptedException {
    		if (listProduct.size() > 100) {
    			System.out.println(getPrefix() + "库存已满,请稍候再生产");
    			wait();
    		}
    
    		listProduct.add(pro);
    		System.out.println(getPrefix() + "生产了:" + pro);
    		notifyAll();// 通知消费者获取产品
    	}
    
    	public synchronized void con() throws InterruptedException {
    		if (listProduct.size() <= 0) {
    			System.out.println(getPrefix() + "库存不足,请及时补货");
    			wait();
    		}
    
    		Integer cur = listProduct.get(0);
    		listProduct.remove(cur);
    		System.out.println(getPrefix() + "取走:" + cur + " 剩余库存:" + listProduct.toString());
    		notifyAll();// 通知生产者生产产品
    	}
    
    	private String getPrefix() {
    		return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss ").format(new Date()) + Thread.currentThread().getName() + " ";
    	}
    }
    

    volatile关键字

    多线程的内存模型:main memory(主存)、working memory(线程栈),线程处理数据时,先把主存中的数据load到本地栈,操作完成后会save回主存,volatile关键词的作用:每次针对该变量的操作都激发一次load and save。
    针对多线程使用的变量如果不是volatile或者final修饰的,很有可能产生不可预知的结果(另一个线程修改了这个值,但是之后在某线程看到的是修改之前的值)。其实道理上讲同一实例的同一属性本身只有一个副本。但是多线程是会缓存值的,本质上,volatile就是不去缓存,直接取值。在线程安全的情况下加volatile会牺牲性能。

    多线程实现

    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    
    public class TestThread {
    	public static void main(String[] args) throws InterruptedException, ExecutionException {
    		// 1、继承Thread类,资源和Thread绑定,资源无法共享
    		new Thread1().start();
    		new Thread1().start();
    
    		// 2、实现Runnable接口,资源和Runnable接口绑定,资源可以共享
    		Thread2 thread2 = new Thread2();
    		new Thread(thread2).start();
    		new Thread(thread2).start();
    
    		// 3、实现Callable<>接口
    		ExecutorService e = Executors.newFixedThreadPool(3);
    		Future future = e.submit(new Thread3());
    		// future.isDone(); // return true,false 无阻塞
    		String str = (String) future.get(); // return 返回值,阻塞直到该线程运行结束
    		System.out.println("主线程结束");
    		System.out.println(str);
    	}
    }
    
    // 1、继承Thread类
    class Thread1 extends Thread {
    	int i = 0;
    
    	@Override
    	public void run() {
    		i++;
    		System.out.println(i);
    	}
    }
    
    // 2、实现Runnable接口
    class Thread2 implements Runnable {
    	int i = 0;
    
    	@Override
    	public void run() {
    		i++;
    		System.out.println(i);
    	}
    }
    
    // 3、实现Callable<>泛型接口
    // 可以在任务结束后提供一个返回值,Runnable不行
    // call方法可以抛出异常,Runnable的run方法不行
    // 可以通过运行Callable得到的Fulture对象监听目标线程调用call方法的结果,得到返回值,(fulture.get(),调用后会阻塞,直到获取到返回值)
    class Thread3 implements Callable<String> {
    
    	@Override
    	public String call() throws Exception {
    		Thread.sleep(3000);
    		System.out.println("子线程结束");
    		return "test";
    	}
    }
    
    

    多线程控制类

    1. ThreadLocal
      保存线程的独立变量。对一个线程类(继承自Thread)
      当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。常用于用户登录控制,如记录session信息。
      实现:每个Thread都持有一个TreadLocalMap类型的变量(该类是一个轻量级的Map,功能与map一样,区别是桶里放的是entry而不是entry的链表。功能还是一个map。)以本身为key,以目标为value。
      主要方法是get()和set(T a),set之后在map里维护一个threadLocal -> a,get时将a返回。ThreadLocal是一个特殊的容器。

    未完待续。。。

  • 相关阅读:
    级联操作
    深入解析http协议
    http状态码
    数据库在一对一、一对多、多对多怎么设计表关系
    [转载]C#深拷贝的方法
    TraceSource记录程序日志
    .NET 垃圾回收与内存泄漏
    DevExpress GridControl使用方法总结
    DevExpress使用技巧总结
    Oracle 错误代码小结
  • 原文地址:https://www.cnblogs.com/yinchh/p/12381089.html
Copyright © 2020-2023  润新知