java 多线程

单例模式

单例模式: 保证一个只能存在一个实例
懒汉: 实例等到调用方法时候创建(调用的时候,最后一刻)线程不安全,效率较高
饿汉式: 类第一次加载之后就会创建实例 线程安全,效率较低
静态的内容(静态变量,静态块),在类第一次加载之后就会初始化

实现方式:
1.构造器私有化(外部才不能通过new随便创建对象,对象只能我[类的内部]来创建,给你)
2.私有的,静态的,该类的引用(存储创建了的对象)
3.对外提供一个公共的静态的访问方式(方法)

饿汉式

public class SingleDemo01 {
	public static void main(String[] args) {
		System.out.println(Single.newInstance());
		System.out.println(Single.newInstance());
		System.out.println(Single.newInstance());
		System.out.println(Single.newInstance());
	}
}


//单例 饿汉式
class Single{
	//2.私有的静态的Single类型的引用
	private static Single single = new Single();  //静态变量会在类第一次加载后初始化,就会创建实例
	
	//1.私有的构造器
	private Single() {
		// TODO Auto-generated constructor stub
	}
	
	//3.公共方法  返回一个当前类型的对象
	public static Single newInstance() {
		return single;
	}
}

懒汉式

public class SingleTonDemo02 {
	public static void main(String[] args) {
		System.out.println(SingleTon.newInstance());
		System.out.println(SingleTon.newInstance());
		System.out.println(SingleTon.newInstance());
		System.out.println(SingleTon.newInstance().message);
	}
}


//懒汉式
class SingleTon{
	//2私有的静态的该类的引用 
	private static SingleTon singleTon;
	
	//1.私有的构造器
	private SingleTon(){}
	
	//3.公共的静态的访问方式,返回该类实例
	public static SingleTon newInstance() {
		//创建对象
		//第一次调用方法时候才创建对象,第二次开始就不创建,因为已经有了,直接返回
		if(singleTon == null) {
			singleTon = new SingleTon();
		}
		return singleTon;
	}
	
	
	//普通的成员变量
	public  String message =  "这是一个单例模式的类";
	//静态变量
	//块
	//构造器(都得是私有的)
	//成员方法
	//静态方法
}

进程

执行中的程序叫做进程(Process),是一个动态的概念。
进程是程序的一次动态执行过程, 占用特定的地址空间.
每个进程由3部分组成:cpu,data,code。每个进程都是独立的,保有自己的cpu时间,代码和数据,即便用
同一份程序产生好几个进程,它们之间还是拥有自己的这3样东西。
多任务(Multitasking)操作系统将CPU时间动态地划分给每个进程,操作系统同时执行多个进程,每个进程独
立运行。以进程的观点来看,它会以为自己独占Cpu的使用权

线程

  • 线程是进程中一个“单一的连续控制流程” (a single sequential flow of control)/执行路径。线程也可以达到同
    一份程序产生好几个进程的效果,但是不同的线程之间可以有某种程度上的资源共享,所以线程又被称为轻
    量级进程(lightweight process)。
  • Threads run at the same time, independently of one another
  • 一个进程可拥有多个并行的(concurrent)线程
  • 一个进程中的线程共享相同的内存单元/内存地址空间可以访问相同的变量和对象,而且它们从同一堆中分配
    对象通信、数据交换、同步操作
  • 由于线程间的通信是在同一地址空间上进行的,所以不需要额外的通信机制,这就使得通信更简便而且信息
    传递的速度也更快。

创建线程

创建Thread的子类

创建: 继承 Thread +重写 run
启动: 创建子类对象 对象.start()
创建 Thread 子类的一个实例并重写 run 方法,run 方法会在调用 start()方法之后被执 行,示例如下:

package day15;

import java.util.stream.DoubleStream;

public class ThreadDemo extends Thread{
    @Override
    public void run() {
        for (int i = 1000; i >=0 ; i--) {
            System.out.println("倒计时: "+i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        Thread thread = new ThreadDemo();
        thread.start();

这种方式的缺点:那就是如果我们的类已经从一个类继承(如小程序必须继承自 Applet 类),则无法再继承Thread 类

通过Runnable接口实现多线程

优点:可以同时实现继承。实现Runnable接口方式要通用一些。

package day15;

import java.util.stream.DoubleStream;

public class ThreadDemo {
    
    public static void main(String[] args) {
        ThreadDemo2 th = new ThreadDemo2();
        Thread th1 = new Thread(th,"Thread1");
        Thread th2 = new Thread(th,"Thread2");
        Thread th3 = new Thread(th,"Thread3");
        th1.start();
        th2.start();
        th3.start();

    }
}

class ThreadDemo2 implements Runnable{
    int tis = 600;
    @Override
    public void run() {
       while (tis > 0){
            System.out.println(Thread.currentThread().getName()+"购票 :"+tis--);
        }
    }
}

线程的五种状态

1)、新生状态: new
2)、就绪状态: runnable
3)、运行状态: running
4)、阻塞状态: blocked
5)、执行完毕: dead

在这里插入图片描述
1)、新生状态:选出运动员
2)、就绪状态:走到起跑线,做好跑的动作,枪响后,不是马上就跑,得有反应时间。
3)、运行状态:反应完成后,开始跑
4)、阻塞状态:路边一个石头绊倒了,马上跑起来,嘟囔几句,踢踢石头, 不是马上跑,重新反应进入就绪。
5)、终止状态:跑完了,结束了,慢慢的走几步停下来。
死亡状态是线程生命周期中的最后一个阶段。线程死亡的原因有两个。一个是正常运行的线程完成了它的全部工
作;另一个是线程被强制性地终止,如通过执行stop或destroy方法来终止一个线程
不建议用 stop destory 方法。

线程同步和死锁问题

synchronized同步

由于我们可以通过 private 关键字来保证数据对象只能被方法访问,所以我们只需针对方法提出一套机制,这套
机制就是 synchronized 关键字,
它包括两种用法:synchronized 方法synchronized 块

synchronized 方法:通过在方法声明中加入 synchronized关键字来声明 synchronized 方法。
如:

public synchronized void accessVal(int newVal);

synchronized 方法控制对类成员变量的访问:每个对象对应一把锁,每个 synchronized 方法都必须获得调用该
方法的对象的锁方能执行,否则所属线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此
后被阻塞的线程方能获得 该锁,重新进入可执行状态。
synchronized 方法的缺陷:若将一个大的方法声明为synchronized 将会大大影响效率,典型地,若将线程类的
方法 run() 声明为 synchronized ,由于在线程的整个生命期内它一直在运行,因此将导致它对本类任何
synchronized 方法的调用都永远不会成功。当然我们可以通过将访问类成员变量的代码放到专门的方法中,将其
声明为 synchronized ,并在主方法中调用来解决这一问题,但是 Java 为我们提供了更好的解决办法,那就是
synchronized 块。
synchronized 块:通过 synchronized关键字来声明

用法:
    同步块
    synchronized(this|.class| 资源(成员属性)){  
 要被你同步控制的代码区域-->有可能 会出现问题的代码区域
}

语法如下:

synchronized(syncObject) 
{ 
//允许访问控制的代码
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值