Java的创建线程,安全,共享资源

  • Post author:
  • Post category:java




内容为线程,同步,线程状态

  • 能够描述Java中多线程运行原理
  • 能够使用继承类的方式创建多线程
  • 能够使用实现接口的方式创建多线程
  • 能够说出实现接口方式的好处
  • 能够解释安全问题的出现的原因
  • 能够使用同步代码块解决线程安全问题
  • 能够使用同步方法解决线程安全问题
  • 能够说出线程6个状态的名称



1.多线程的原理:

  • 我理解为在主方法中(也就是主线程)开启另一个线程,使得cup执行程序是在多个线程之间高速度切换,以完成多任务,足以满足多用户的需求.
  • java程序是多线程的 ,其采用了更传统的顺序语言的基础上提供了对多线程的支持,并且每个任务开启时都会在内存空间中有自己的地址去执行,因此任务之间根本不能相互干涉,并且其也没有相互干涉的必要性,所以安全性较高.
  • 基本的线程机制:并发编程使我们可以将程序划分为多个分离的,独立运行的任务.通过使用多线程机制,这些独立任务(在Java中也称为子任务或子线程)中的每一个都将由执行线程来驱动.一个线程就是在进程种的一个单一的顺序控制流,因此单个线程可以拥有多个并发执行任务.就像是每个任务都是有自己的cup一样,但其实底层的机制是切分cup的时间,单个cup快速且随机的执行不同的任务.



下面是一个简单的多线程例子,并打印运行的结果看cpu是如何在两个线程中切换的

//这是一个自定义线程类
public class ThreadRun implements Runnable {
//这里必须继承 Runnable 接口
//并重写run方法 作为此线程的执行方法体
    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            System.out.println("我是子线程" + i);
        }
    }
}
---------------------------------------------------------------------------
---------------------------------------------------------------------------
//这是一个测试类
public class domain {
    public static void main(String[] args) {
        //这是main方法 也叫主线程
        ThreadRun threadRun = new ThreadRun();
        Thread thread = new Thread(threadRun);
        //开启一个线程
        thread.start();
        //开启线程后主方法会继续往下运行,这是会出现子线程和主线程抢夺cup的情况
        for (int i = 0; i < 50; i++) {
            System.out.println("我是主线程"+ i);
        }
    }
}

执行结果分析:

在这里插入图片描述



2.Thread类

  • 使用继承类,并创建线程:

    1.Thread中可以去查API了解更多的构造方法

    2.两种创建线程的方法:

    1. 一种是继承Thread类方式,
    2. 一种是实现Runnable接口方式,



3.实现Runnable接口比继承Thread类所具有的优势

  • 如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享
    1. 适合多个相同的程序代码的线程去共享同一个资源。
    1. 可以避免java中的单继承的局限性。
    1. 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立。
    1. 线程池只能放入实现Runable或Callable类线程,不能直接放入继承Thread的类


下面要用到资源共享,在这补充

  • 资源共享,涉及到创建线程的方式,
  • 第一种继承Thread的每一次创建线程都会通过new Thread的继承类,在内存空间中开辟出独立的地址去执行自己的任务
  • 第二种实现Runnable接口,每一个线程都实现同一个接口,总共的资源量是不变的,这个不变的总资源量可以是实现类中的成员属性 (例如我下面的买票总共100张),把任务类(Runnable的实现类)交给线程,再开启线程,他们执行的是一个任务,所以共享了这100张票…



4.匿名内部类的创建方法,介入lambda表达式

  • 匿名内部类,匿名对象的创建方法
public class NoNameInnerClassThread {
public static void main(String[] args) {
	// new Runnable(){
	// 		public void run(){
	// 			for (int i = 0; i < 20; i++) {
	// 				System.out.println("张宇:"+i);
	// 				}
	// 			}
	// 		}; //‐‐‐这个整体 相当于new MyRunnable() 
				//---这也是一个匿名内部类匿名对象
				//这种方法 会在.out文件创建一个.class的字节码文件
				//如果想提高性能 可以使用lambda表达式
/**
*lambda表达式注重的是方法体,在乎的是结果,并且不会在.out文件夹中创建.class字节码文件,所以效率更高,书写更为简单
*/
	 new Thread(() -> {
            for (int i = 0; i < 20; i++) {
                System.out.println("张宇:" + i);
            }
        }).start();

//下面是lambda展开的全部样子 较为好理解
/*Runnable r = new Runnable(){
	public void run(){
		for (int i = 0; i < 20; i++) {
		System.out.println("张宇:"+i);
			}
	}
};
new Thread(r).start();
*/
//下面是主线程
	for (int i = 0; i < 20; i++) {
		System.out.println("费玉清:"+i);
		}
	}
}



5.线程安全

  • 如果有多个线程在同时运行,而这些线程可能会同时运行这段代码。程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
  • 简单举一个例子:卖电影票是一个很好的例子,假设有两个售票员,一个叫小阳阳,一个小檀檀,有许多人在买票入场看电影,如果不出现票座位的重复,保证每个买到票的都有相应座位,则我就可以称这两个售票员,也就是两个线程是安全的


    <下面代码块中备注详解怎样使线程安全>


这个是实现Runnable接口的实现类

 /**
 *		就以买票为例 --一共100张:
 *      两个买票员不能卖出同一张票,不能冲突,那么用线程的角度来说,当小檀檀出售A4这个座位的票的过程中,小阳阳不能卖这张票
 *      所以当第一线程抢到cpu时,第二线程不能抢夺cpu,需第一线程卖完一张票后释放cpu后,在同一起跑线上和第二线程在抢夺cpu
 *      两个线程再次买票,看黄牛顾客(cpu)到哪个窗口买票,这里当然是随机的
 */
public class ThreadRun implements Runnable {
    private int ticket = 100;
    /*
     * 执行卖票操作
     */
    @Override
    public void run() {
//每个窗口卖票的操作
//窗口 永远开启
        while (true) {
            if (ticket > 0) {//有票 可以卖
//出票操作
//使用sleep模拟一下出票时间
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
//获取当前线程对象的名字
                String name = Thread.currentThread().getName();
                System.out.println(name + "正在卖:" + ticket--);
            }
        }
    }

}


下面是domain测试类

public class domain {
    public static void main(String[] args) {
        //创建线程任务对象
        ThreadRun ticket = new ThreadRun();
//创建两个窗口对象
        Thread t1 = new Thread(ticket, "小檀檀窗口1");
        Thread t2 = new Thread(ticket, "小阳阳窗口2");
//同时卖票
        t1.start();
        t2.start();
    }
}


后面的线程的状态和同步,锁独立写出自己的笔记和理解



版权声明:本文为weixin_41675375原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。