文档章节

多线程

JAVA码猿
 JAVA码猿
发布于 2017/07/19 13:16
字数 1836
阅读 6
收藏 0

系统的应用程序是以进程存在的,而进程的任务则是由线程执行的

    进程 cpu 硬盘读写 CPU 分时间段 进行二进制加法运算 很多进程运行 cpu 负责分配时间段给进程用 时间段进行来回切换 CPU 进行调度 在不同的时间碎片 就是不同的进程。

    线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。 一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源, 但它可与同属一个进程的其它线程共享进程所拥有的全部资源。

多线程应用 任务执行时间  线程执行进程里的运算。

     一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。 由于线程之间的相互制约,致使线程在运行中呈现出间断性。在一个程序中至少有一个进程,而一个进程可以存在多个线程,但至少有一个线程。

 线程也有就绪、阻塞和运行三种基本状态。每一个程序都至少有一个线程,那就是程序本身

进程与线程的运行主要是由系统的CPU进行资源的分配决定的

线程的创建有两种,一种是继承Thread类,重写run方法;另一种是实现Runnable接口,重写run方法

多线程的作用就是多部分代码可以实现同时进行,每个线程都有自己要所要运行的独有的内容,都写在run方法中。

线程开启的标志是调用start()方法,而不是直接调用run()方法,直接调用run方法相当于是在主线程中调用了线程类的一个普通方法,没有达到开线程的目的。

一个进程中所包含的线程的数量是由系统的CPU决定的,并不是线程越多越好,是否要开启多线程是根据任务执行时间的长短决定的。

    如果任务执行时间短,则没有必要开启多线程,因为开启多个线程,CPU在线程之间分配资源时也是会耗费资源的,执行时间短的话,开启多线程则不是很有必要。

并行与并发:并行简单来说就是在同一时间段内同时进行,而并发的意思则是同时发生;并行就是在同一时间点内,多个线程同时进行;并发则是线程之间互相切换,存在时间间隔。

单核电脑不支持多线程。

线程的生命周期:新生(new线程对象时),就绪(调用start()后),运行(CPU将资源分配给线程后),阻塞(休眠、等待、读取I\O时阻塞),死亡。

阻塞 线程读取文件 数据库 需要一定的时间 io层面开销时间长 
线程执行时间较长 阻塞。

休眠和等待的区别:线程休眠(sleep)后,到达设定的时间后就会自动唤醒,重新回到运行状态,睡眠时不会释放系统资源;线程进入等待(wait)状态后,如果不主动调用notify方法进行唤醒,线程就会一直等待下去,线程在进入到等待状态后,释放系统资源,唤醒后重新进入到就绪状态。

线程中断:推荐将线程执行的任务写到一个无限循环中,设计一个标示符来进行线程的控制

线程安全问题产生的原因:多个线程同时操作同一个数据,即在一个线程在执行操作共享数据时,有其他的线程参与进来,容易产生线程安全问题。

解决线程安全问题的方法:可以使用同步代码块(或者同步代码方法)即加锁,synchronized(入参为对象、字节码){线程所要执行的任务 }; 

线程的优先级:优先级 范围是1-10 数字越大优先级越高 默认是5 新产生的线程继承父类的优先级。

线程安全问题来源于两个线程同时存取单一对象的数据。

多个同步方法锁的资源时统一资源时,那么这些方法是不能够被同时进行的,互相排斥,不可并发。

好的,同志们 。我们一起来填坑.......

package com.dayuanit.thread;

public class NewThread implements Runnable { // 实现Runnable接口

	private Bank bank;

	public NewThread(Bank bank) {
		this.bank = bank;
	}


	public void run() { // 用start()方法线程开启后,调用run()方法来运行 run()方法是当前线程的方法
			// 当一个线程进入 其他的线程处于阻塞状态;
			bank.save1(10);

			bank.save(10);

			System.out.println("账户余额为:" + bank.getAccount());

		

	}
}
package com.dayuanit.thread;

public class Bank {
		private int account = 100;

		public int getAccount() {
			return account;
		}

		public synchronized void save(int money) { // 方法锁 同步代码方法
			System.out.println(Thread.currentThread().getName() + " 方法锁 进来啦");
			account += money;
			System.out.println(Thread.currentThread().getName() + "方法锁 结束啦");
		}

		public void save1(int money) {  // 锁对象 锁代码块里的内容 同步代码块
			synchronized (this) {
				System.out.println(Thread.currentThread().getName() + "锁对象 进来啦");
				account += money;
				System.out.println(Thread.currentThread().getName() + "锁对象 结束啦");
			}

		}

}
package com.dayuanit.thread;

public class TestThread {
	public static void main(String[] args) { // main 方法 jvm 调用  (主线程)
		System.out.println(Thread.currentThread().getName());
		Bank bank = new Bank(); // 创建bank实例
		NewThread thread = new NewThread(bank);

		for (int i = 0; i < 4; i++) { // 开启4个线程;
			new Thread(thread).start(); // 线程启动未必执行 等待CPU调度  需要调用run()方法;
		}
		
	}
}
	

好的 我们一起来看结果:

注意看 run()方法是由线程调度使用,对同一资源进行利用时,总是排队,一个一个来。多个线程不可以同一个同步方法。同步静态的方法时是锁的字节码,同步非静态方法时锁的是当前对象。

用synchronized来同步方法或者代码块,避免线程不安全的问题。

我们对字节码和对象同步,运行时怎么回事呢?

package com.dayuanit.run;


public class MyRun implements Runnable {

	private boolean flag = true;

	public void setFlag(boolean flag) {
		this.flag = flag;
	}

	public boolean isFlag() {
		return flag;
	}

	public void run() {
		while (true) {
			if (isFlag()) {
					
				a();
				b();
				
			}
			break; // 跳出当前循环;
		}
	}

	public void a() {
		synchronized (MyRun.class) {
			System.out.println("a 线程开启 ");

			try {
				Thread.sleep(5000);
			} catch (InterruptedException ie) {
				ie.printStackTrace();
			}             
			System.out.println(" a线程结束");
			System.out.println();
		}
	}

	public void b() {
		synchronized (this) {
			System.out.println("b 线程开始 ");
			try {
				Thread.sleep(5000);
			} catch (InterruptedException ie) {
				ie.printStackTrace();
			}
			System.out.println(" b线程结束");
			System.out.println();
		} 
	}


}

注意 线程中断:推荐将线程执行的任务写到一个无限循环中,设计一个标示符来进行线程的控制

package com.dayuanit.run;



public class TestRun {
	public static void main(String[] args) {

		 MyRun myRun = new MyRun();

		for (int i = 0; i < 10; i++) { // 开启10个线程 
			new Thread(myRun).start();
		}

		try {
			Thread.sleep(1000);    // sleep 休眠 不释放资源 自动苏醒 wait 等待 释放资源 需要 notify 唤醒
		} catch (InterruptedException ie) {
			ie.printStackTrace();
		}

		System.out.println(Thread.currentThread().getName()); // 注意看结果 主线程 名字 main

		myRun.setFlag(false);

	}
}

结果在下面:

main 主线程名字,a()方法锁的是当前对象的字节码文件,b()方法锁的是当前对象。

© 著作权归作者所有

JAVA码猿
粉丝 9
博文 62
码字总数 45401
作品 0
海淀
程序员
私信 提问

暂无文章

分布式协调服务zookeeper

ps.本文为《从Paxos到Zookeeper 分布式一致性原理与实践》笔记之一 ZooKeeper ZooKeeper曾是Apache Hadoop的一个子项目,是一个典型的分布式数据一致性的解决方案,分布式应用程序可以基于它...

ls_cherish
今天
4
0
redis 学习2

网站 启动 服务端 启动redis 服务端 在redis 安装目录下 src 里面 ./redis-server & 可以指定 配置文件或者端口 客户端 在 redis 的安装目录里面的 src 里面 ./redis-cli 可以指定 指定 连接...

之渊
昨天
2
0
Spring boot 静态资源访问

0. 两个配置 spring.mvc.static-path-patternspring.resources.static-locations 1. application中需要先行的两个配置项 1.1 spring.mvc.static-path-pattern 这个配置项是告诉springboo......

moon888
昨天
4
0
hash slot(虚拟桶)

在分布式集群中,如何保证相同请求落到相同的机器上,并且后面的集群机器可以尽可能的均分请求,并且当扩容或down机的情况下能对原有集群影响最小。 round robin算法:是把数据mod后直接映射...

李朝强
昨天
4
0
Kafka 原理和实战

本文首发于 vivo互联网技术 微信公众号 https://mp.weixin.qq.com/s/bV8AhqAjQp4a_iXRfobkCQ 作者简介:郑志彬,毕业于华南理工大学计算机科学与技术(双语班)。先后从事过电子商务、开放平...

vivo互联网技术
昨天
24
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部