多线程的创建和不安全问题解决方案

多线程的创建和不安全问题解决方案

      • 1.多线程
        • 1.1 多线程的优缺点
        • 1.2创建线程
          • 1.2.1三种主要方式
      • 2.多线程处理同一资源解决安全问题
        • 2.1 同步代码块
        • 2.2 同步方法
        • 2.3 Lock锁
      • 3.处理安全问题实现代码演示:
        • 3.1同步执行代码
        • 3.2同步方法
        • 3.3Lock锁机制

1.多线程

多线程的创建和不安全问题解决方案_第1张图片

1.1 多线程的优缺点

优点:
      1. 提升资源利用率
	  2. 提高用户体验
	  3.一般线程之间比较独立,互不影响
      4.一个线程发生问题,一般不影响其它线程

缺点:
	  1. 降低了其他线程的执行概率
	  2. 用户会感受到软件的卡顿问题
	  3. 增加的系统,资源压力
	  4. 多线程情况下的共享资源问题,线程冲突,线程安全问题

1.2创建线程

1.2.1三种主要方式

• 继承 Thread
• 实现 Runable
• 实现 Callable

class Thread类
	Java中的一个线程类
	Thread类是Runnable接口的实现类,同时提供了很多线程的操作使用的方法。
方式一:
	   自定义线程类,继承继成java.lang.Thread类,重写run方法
	创建自定义线程对象,直接调用start方法,开启线程
 
interface Runnable接口
	这里规定了what will be run?
	里面只有一个方法 run方法
方式二:
	自定义线程类,遵从Runnable接口
	使用自定义遵从接口Runnable实现类对象,作为Thread构造方法参数
	借助于Thread类对象和start方法,开启线程

 java.util.concurrent.Callable工具类
方式三:
    从继承Thread类和实现Runnable接口可以看出,上述两种方法都不能有返回值,且不能声明抛出异常。
    而Callable接口则实现了此两点,Callable接口如同Runable接口的升级版,其提供的call()方法将作为线程的执行体,同时允许有返回值。
  但是Callable对象不能直接作为Thread对象的target,因为Callable接口是 Java 5 新增的接口,不是Runnable接口的子接口。
对于这个问题的解决方案,就引入 Future接口,此接口可以接受call() 的返回值,RunnableFuture接口
是Future接口和Runnable接口的子接口,可以作为Thread对象的target 。并且, Future 接口提供了一个实现类:FutureTask 。
FutureTask实现了RunnableFuture接口,可以作为 Thread对象的target。

     实现Callable接口,重写call()方法,然后包装成java.util.concurrent.FutureTask, 再然后包装成Thread

Callable: ()

public class Main {
    public static void main(String[] args) throws Exception {
    	 // 将Callable包装成FutureTask,FutureTask也是一种Runnable
        MyCallable callable = new MyCallable();
        FutureTask futureTask = new FutureTask<>(callable);
        new Thread(futureTask).start();

        // get方法会阻塞调用的线程
        Integer sum = futureTask.get();
        System.out.println(Thread.currentThread().getName() + Thread.currentThread().getId() + "=" + sum);
    }
}
class MyCallable implements Callable {
    @Override
    public Integer call() throws Exception {
        System.out.println(Thread.currentThread().getName() + "\t" + new Date() + " \tstarting...");
       int sum = 0;
        for (int i = 0; i <= 30; i++) {
            sum += i;
        }
        Thread.sleep(500);

        System.out.println(Thread.currentThread().getName() + "\t" + new Date() + " \tover...");
        return sum;
    }
}

创建代码

2.多线程处理同一资源解决安全问题

造成安全性的必要条件

• 多线程环境 —存在多线程
• 多个线程操作共享数据—访问同一个资源
• 操作共享数据的语句不是原子性的(多条语句操作该资源)

具体解决办法:

2.1 同步代码块

synchronized (/* 锁对象 */) {
    
}

/*
特征:
 	1. synchronized 小括号里面的对象是锁对象,并且要求如果是多线程的情况下,锁对象必须是同一个对象。
 	2. synchronized 大括号中的代码块就是需要进行同步的代码,或者说是加锁的代码,大括号里面的内容,有且只允许一个线程进入。
 	3. 同步代码块越短越好,在保证安全的情况下,提高性能
 
问题:
	1. 目前锁对象感觉很随意,存在一定的隐患
	2. 代码层级关系很复杂,看着有点麻烦
*/

2.2 同步方法

synchronized 作为关键字来修饰方法,修饰的方法就是对应的同步方
有且只允许一个线程进入,到底是谁来完成的加锁操作?

1. 静态成员方法
	锁对象,是当前类对应的字节码文件.class 类名.class
2. 非静态成员方法
	锁对象就是当前类对象 this

选择同步方法是否使用static修饰问题
	1. 如果非static修饰,要保证执行的线程对象有且只有一个,因为锁对象就是当前线程对象
	2. 如果是static修饰,锁对象具有唯一性,多个线程使用的锁是同一个锁。

2.3 Lock锁

Java提供了一个对于线程安全问题,加锁操作相对于同步代码块和同步方法更加广泛的一种操作方式。
1. 对象化操作。
	创建Lock构造方法
		Lock lock = new ReentrantLock();
2. 方法化操作。
	开锁:
		unlock();
	加锁:
		lock();

3.处理安全问题实现代码演示:

创建案例;业务窗口办理卖票业务

3.1同步执行代码

// 
/*
 * 设置同步代码块(同步锁)。
synchronized(共享资源){
同步执行代码;
 */
public class Sell2Tickets implements Runnable{
	private static int tickers=30;
       private Object obj=new Object();
	public void run(){
		while(true){
			try {
				Thread.sleep(500);//延时
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			};
			synchronized(this){//同步代码块
				if(tickers>0)
			System.out.println(Thread.currentThread().getName()+"当前出售第"+(tickers--)+"张票");
                    //Thread.currentThread().getName() 拿到当前线程的引用和名称
			}
			}
	}
}

3.2同步方法

// 
/*
 * 设置同步方法。
 */
public class Sell3Tickets implements Runnable{

	private static int tickers=30;
	public void run(){
	   for(int i=0;i<30;i++){
		   syMethod();
	   }
			
             
    }

	synchronized private void syMethod() {
       
			
			try {
				Thread.sleep(500);//延时
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			};
				if(tickers>0)
					System.out.println(Thread.currentThread().getName()+"当前出售第"+(tickers--)+"张票");
                    //Thread.currentThread().getName() 拿到当前线程的引用和名称
			}
}

//静态方法
//
/*
 * 设置同步方法。
 */
public class Sell3Tickets implements Runnable{

	private static int tickers=30;
	private int x = 0;
	public void run(){
		while (true) {
			if(x % 3 == 0){
				//同步代码块实现同步.这里设置的锁对象是该类的字节码文件对象。
				synchronized (Sell3Tickets.class) {
					if (tickers > 0) {
						try {
							// 模拟售票过程
							Thread.sleep(100);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
						System.out.println(Thread.currentThread().getName() + "正在卖第:"
								+ tickers-- + "张票");
					}
				}
			}else{
				syMethod();
			}
			x++;
		}
	}

  

	synchronized private static void syMethod() {
       
			
			try {
				Thread.sleep(500);//延时
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			};
			
				if(tickers>0)
					System.out.println(Thread.currentThread().getName()+"当前出售第"+(tickers--)+"张票");
                    //Thread.currentThread().getName() 拿到当前线程的引用和名称
			}
			
}


3.3Lock锁机制

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
//
/*
 * 锁机制
 */
public class Sell4Tickets implements Runnable{

	private static int tickers=30;
	//创建一个锁对象
	private final Lock lock = new ReentrantLock();
	public void run(){
	   for(int i=0;i<30;i++)
		   syMethod();     
    }

	 private void syMethod() {
       
		    //进入代码块之后立马加锁
			lock.lock();//获取锁
				if(tickers>0)
					try {
						Thread.sleep(500);//延时
						System.out.println(Thread.currentThread().getName()+"当前出售第"+(tickers--)+"张票");
	                    //Thread.currentThread().getName() 拿到当前线程的引用和名称
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}finally{
						
						lock.unlock();
					}
				    
					}
			
}

参考:
多线程及线程安全问题解决方案

深入学习推荐博文:
https://blog.csdn.net/vbirdbest/article/details/81282163

你可能感兴趣的:(多线程&&高并发)