Java线程总结---第一天
线程和进程各自有什么区别和优劣:
进程是资源分配的最小单位,线程是程序执行的最小单位
进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段,这种操作非常昂贵。而线程是共享进程中的数据的,使用相同的地址空间,因此CPU切换一个线程的花费远比进程要小很多,同时创建一个线程的开销也比进程要小很多,线程的上下文切换的性能消耗要小于进程。
线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据。
多进程程序更健壮,多线程程序只要有一个线程死掉,整个进程也死掉了,而一个进程死掉并不会对另外一个进程造成影响,因为进程有自己独立的地址空间。
并行与并发
并发是没有时间上的重叠的,两个任务是交替执行的,由于切换的非常快,对于外界调用者来说相当于同一时刻多个任务一起执行了;而并行可以看到时间上是由重叠的,也就是说并行才是真正意义上的同一时刻可以有多个任务同时执行。
小程序demo
public class Demo extends Thread {
@Override
public void run() {
while (true){
System.out.println(this.currentThread().getName());
}
}
public static void main(String[] args) {
Demo demo= new Demo();
demo.start();
}
}
public class Demo implements Runnable {
@Override
public void run() {
while (true){
System.out.println("hello thread");
}
}
public static void main(String[] args) {
Demo demo= new Demo();
Thread thread=new Thread(demo,"t1");
thread.start();
}
}
public class Demo{
public int count = 0;
public void print() {
while (true){
System.out.println(count++);
}
}
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
new Demo().print();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
new Demo().print();
}
}).start();
}
}
synchronized锁范围
普通同步方法,锁是当前实例对象
静态同步方法,锁是当前类的class对象
同步方法块,锁是括号里面的对象
public class Demo{
public synchronized void synsMethod1(){
System.out.println("method1---");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synsMethod3();
}
public synchronized void synsMethod2(){
System.out.println("method2---");
}
public synchronized void synsMethod3(){
System.out.println(www.yaxingyule.cn"method3---");
}
public static void main(String[] args) {
Demo demo=new Demo( www.yingxionghui1.cn);
new Thread(new Runnable() {
@Override
public void run() {
demo.synsMethod1();
}
}).start();
new Thread(new Runnable() {
@Override
public void run(www.tiaotiaoylzc.com) {
demo.synsMethod2();
}
}).start();
}
}
输出结果
method1---
method3---
method2---
再如下
public class Demo{
public synchronized void synsMethod1(){
System.out.println("method1---");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace(www.mytxyl1.com);
}
synsMethod3();
}
public synchronized www.dituyule.org static void synsMethod2(){
System.out.println("method2-www.yongshi123.cn--");
}
public synchronized void synsMethod3(){
System.out.println("method3---");
}
public static void main(String[] args) {
Demo demo=new Demo();
new Thread(new Runnable() {
@Override
public void run() {
demo.synsMethod1();
}
}).start();
new Thread(new Runnable() {
@Override
public void run(www.ouyi3pt1.cn) {
demo.synsMethod2();
}
}).start();
}
}
输出结果(其中一种可能)
method1---
method2---
method3---
所以说静态方法的锁和非静态方法的锁是不一样的
Synchronized锁重入
关键字Synchronized拥有锁重入的功能,也就是在使用Synchronized的时候, 当一个线程得到一个对象的锁后,在该锁里执行代码的时候可以再次请求该对象的锁 时可以再次得到该对象的锁。
当线程请求一个由其它线程持有的对象锁时,该线程会阻塞,而当线程请求由自己持有的对象锁时,如果该锁是重入锁,请求就会成功,否则阻塞。
一个简单的例子就是:在一个Synchronized修饰的方法或代码块的内部调用本 类的其他Synchronized修饰的方法或代码块时,是永远可以得到锁的。
/**
* @program: demo
* @description:
* @author: lee
* @create: 2019-02-25
**/
public class Demo{
public synchronized www.yigouyule2.cn void synsMethod1(){
System.out.println("method1---");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synsMethod2();
}
public synchronized void synsMethod2(){
System.out.println("method2---");
}
public static void main(String[] args) {
Demo demo=new Demo();
new Thread(new Runnable() {
@Override
public void run() {
demo.synsMethod1();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
demo.synsMethod2();
}
}).start();
}
}
为什么要引入可重入锁这种机制哪?
假如有一个线程T获得了对象A的锁,那么该线程T如果在未释放前再次请求该对象的锁时,如果没有可重入锁的机制,是不会获取到锁的,这样的话就会出现死锁的情况,所以最大的作用是避免死锁。
volatile与synchronized的
volatile关键字的作用就是强制从公共堆栈中取得变量的值,而不是线程私有的数据栈中取得变量的值。
关键字volatile是线程同步的轻量级实现,性能比synchronized要好,并且volatile只能修饰变量,而synchronized可以修饰方法,代码块等。
多线程访问volatile不会发生阻塞,而synchronized会发生阻塞。
volatile可以保证数据的可见性,但不可以保证原子性(不是线程安全的),而synchronized可以保证原子性,也可以间接保证可见性,因为他会将私有内存和公共内存中的数据做同步。
volatile解决的是变量在多个线程之间的可见性,而synchronized解决的是多个线程之间访问资源的同步性。
ThreadLocal
ThreadLocal提供了线程的局部变量,每个线程都可以通过set()和get()来对这个局部变量进行操作,但不会和其他线程的局部变量进行冲突,实现了线程的数据隔离。
简要言之:往ThreadLocal中填充的变量属于当前线程,该变量对其他线程而言是隔离的。
最典型的应用
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/**
* 采用ThreadLocal封装Connection
*
* @author Administrator
*
*/
public class ConnectionManager {
//定义ThreadLocal静态变量,确定存取类型为Connection
private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>();
/**
* 得到Connection
* @return
*/
public static Connection getConnection() {
Connection conn = connectionHolder.get();
//如果在当前线程中没有绑定相应的Connection
if (conn == null) {
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
String url = "jdbc:oracle:thin:@localhost:1521:bjpowern";
String username = "drp1";
String password = "drp1";
conn = DriverManager.getConnection(url, username, password);
//将Connection设置到ThreadLocal
connectionHolder.set(conn);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
return conn;
}
/**
* 关闭数据库连接方法
* @return
*/
public static void closeConnection() {
Connection conn = connectionHolder.get();
if (conn != null) {
try {
conn.close();
//从ThreadLocal中清除Connection
connectionHolder.remove();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* 关闭数据库连接方法
* @return
*/
public static void close(Connection conn) {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void close(Statement pstmt) {
if (pstmt != null) {
try {
pstmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void close(ResultSet rs ) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* 事务开启
* @return
*/
public static void beginTransaction(Connection conn) {
try {
if (conn != null) {
if (conn.getAutoCommit()) {
conn.setAutoCommit(false); //手动提交
}
}
}catch(SQLException e) {}
}
/**
* 事务提交
* @return
*/
public static void commitTransaction(Connection conn) {
try {
if (conn != null) {
if (!conn.getAutoCommit()) {
conn.commit();
}
}
}catch(SQLException e) {}
}
/**
* 事务回滚
* @return
*/
public static void rollbackTransaction(Connection conn) {
try {
if (conn != null) {
if (!conn.getAutoCommit()) {
conn.rollback();
}
}
}catch(SQLException e) {}
}
}
初始化默认值
public class ThreadlLocalDemo {
/**
* 初始化一个ThreadLocal对象,并且初始值设置为0
*/
private static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
return 0;
}
};
public int getNextNumber() {
threadLocal.set(threadLocal.get() + 1);
return threadLocal.get();
}
static class DemoThread extends Thread {
ThreadlLocalDemo threadlLocalDemo = null;
public DemoThread(ThreadlLocalDemo localDemo) {
this.threadlLocalDemo = localDemo;
}
@Override
public void run() {
for (int i = 0; i < 5; i++) { // 每个线程打印 5个值
System.out.println("Thread:" + Thread.currentThread().getName()
+ ",threadlLocalDemo:" + threadlLocalDemo.getNextNumber());
}
}
}
public static void main(String[] args) {
ThreadlLocalDemo threadlLocalDemo = new ThreadlLocalDemo();
DemoThread demoThread = new DemoThread(threadlLocalDemo);
DemoThread demoThread2 = new DemoThread(threadlLocalDemo);
DemoThread demoThread3 = new DemoThread(threadlLocalDemo);
DemoThread demoThread4 = new DemoThread(threadlLocalDemo);
demoThread.start();
demoThread2.start();
demoThread3.start();
demoThread4.start();
}
}
ThreadLocal实现的原理
首先,我们来看一下ThreadLocal的set()方法,因为我们一般使用都是new完对象,就往里边set对象了
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
上面有个ThreadLocalMap,我们去看看这是什么?
static class ThreadLocalMap {
/**
* The entries in this hash map extend WeakReference, using
* its main ref field as the key (which is always a
* ThreadLocal object). Note that null keys (i.e. entry.get()
* == null) mean that the key is no longer referenced, so the
* entry can be expunged from table. Such entries are referred to
* as "stale entries" in the code that follows.
*/
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
/**
* Construct a new map initially containing (firstKey, firstValue).
* ThreadLocalMaps are constructed lazily, so we only create
* one when we have at least one entry to put in it.
*/
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
table = new Entry[INITIAL_CAPACITY];
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
table[i] = new Entry(firstKey, firstValue);
size = 1;
setThreshold(INITIAL_CAPACITY);
}
//....很长
}
通过上面我们可以发现的是ThreadLocalMap是ThreadLocal的一个内部类。用Entry类来进行存储
我们的值都是存储到这个Map上的,key是当前ThreadLocal对象!
如果该Map不存在,则初始化一个:
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
如果map存在
/**
* Get the map associated with a ThreadLocal. Overridden in
* InheritableThreadLocal.
*
* @param t the current thread
* @return the map
*/
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
Thread维护了ThreadLocalMap变量
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null
从上面又可以看出,ThreadLocalMap是在ThreadLocal中使用内部类来编写的,但对象的引用是在Thread中! 于是我们可以总结出:Thread为每个线程维护了ThreadLocalMap这么一个Map,而ThreadLocalMap的key是LocalThread对象本身,value则是要存储的对象。
有了上面的基础,我们看get()方法就一点都不难理解了:
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
ThreadLocal原理总结
每个Thread维护着一个ThreadLocalMap的引用
ThreadLocalMap是ThreadLocal的内部类,用Entry来进行存储
调用ThreadLocal的set()方法时,实际上就是往ThreadLocalMap设置值,key是ThreadLocal对象,值是传递进来的对象
调用ThreadLocal的get()方法时,实际上就是往ThreadLocalMap获取值,key是ThreadLocal对象
ThreadLocal本身并不存储值,它只是作为一个key来让线程从ThreadLocalMap获取value。
Java线程总结---第一天的更多相关文章
- Java线程入门第一篇
Java线程的状态有6种 1. 初始(NEW):新创建了一个线程对象,但还没有调用start()方法. 2. 运行(RUNNABLE):Java线程中将就绪(ready)和运行中(running) ...
- java 线程池第一篇 之 ThreadPoolExcutor
一:什么是线程池? java 线程池是将大量的线程集中管理的类,包括对线程的创建,资源的管理,线程生命周期的管理.当系统中存在大量的异步任务的时候就考虑使用java线程池管理所有的线程.减少系统资源的 ...
- java线程学习第一天__低配版的卖面包机
package Thread;import javax.xml.bind.ValidationEvent;class snacks{ private int SaledSnacks=0; ...
- Java 线程--实现java.lang.Runnable接口实现线程
Java线程的第一种实现方式,主要分两步,第一步是继承java.lang.Thread; 第二步是重写run()方法.接下来我们来看Java线程的第二种实现方式,也是分为两步,第一步,写一个类实现ja ...
- Java线程的概念
1. 计算机系统 使用高速缓存来作为内存与处理器之间的缓冲,将运算需要用到的数据复制到缓存中,让计算能快速进行:当运算结束后再从缓存同步回内存之中,这样处理器就无需等待缓慢的内存读写了. 缓 ...
- 第24章 java线程(3)-线程的生命周期
java线程(3)-线程的生命周期 1.两种生命周期流转图 ** 生命周期:**一个事物冲从出生的那一刻开始到最终死亡中间的过程 在事物的漫长的生命周期过程中,总会经历不同的状态(婴儿状态/青少年状态 ...
- 第23章 java线程通信——生产者/消费者模型案例
第23章 java线程通信--生产者/消费者模型案例 1.案例: package com.rocco; /** * 生产者消费者问题,涉及到几个类 * 第一,这个问题本身就是一个类,即主类 * 第二, ...
- Java线程新特征——Java并发库
一.线程池 Sun在Java5中,对Java线程的类库做了大量的扩展,其中线程池就是Java5的新特征之一,除了线程池之外,还有很多多线程相关的内容,为多线程的编程带来了极大便利.为了编写高效稳定 ...
- Java线程间通信方式剖析——Java进阶(四)
原创文章,同步发自作者个人博客,转载请在文章开头处以超链接注明出处 http://www.jasongj.com/java/thread_communication/ CountDownLatch C ...
随机推荐
- 2017-2018-2 20155203《网络对抗技术》Exp2 后门原理与实践
基础问题回答 (1)例举你能想到的一个后门进入到你系统中的可能方式? 通过下载带后门的程序或者点开带有后门的软件,或者后门本身就在我的系统里: (2)例举你知道的后门如何启动起来(win及linux) ...
- 20155323刘威良《网络对抗》Exp8 Web基础
20155323刘威良<网络对抗>Exp8 Web基础 实践内容 (1).Web前端HTML(0.5分) 能正常安装.启停Apache.理解HTML,理解表单,理解GET与POST方法,编 ...
- 汇编-MOV指令
知识点: MOV指令 基址 内联汇编 把OD附加到资源管理器右键菜单 一.MOV指令 aaa=0x889977;//MOV DWORD PTR DS:[0x403018],0x8899 ...
- REST-framework快速构建API--频率
前面已经了解了API的认证和授权.认证,是对资源访问者的第一道门,必须有钥匙,你才能进来拿我的资源:授权,是对资源访问者的第二道门,虽然你进来了,但是你可以拿走什么资源,还是我说了算,就是授权. 当然 ...
- CSS 天坑 I - 字体单位
首先,本文所讨论的“坑”是在做回应式网页设计( Responsive Web Design 以下简称 RWD)时显现的,如果你还只是在做传统的Web设计这算不上是一个坑,因为传统的Web页面是死的,不 ...
- 利用Junit实现eclipse单元测试
在eclipse中使用Junit进行单元测试 今天学会了用Junit在eclipse中进行单元测试,代码的测试工作,在整个软件开发中占有总要的地位,无论是代码开发阶段,还是代码维护阶段.另外边开发边测 ...
- chrome浏览器插件 Octotree 让你浏览GitHub的时候像IDE 一样提供项目目录
GitHub 作为代码托管平台,竟然没有提供项目目录,方便用户在线快速浏览项目结构.所以,在线分析项目源码就会变得很繁琐,必须一层一层点击,然后再一次一次地向上返回.要知道,本来 GitHub 网站在 ...
- 用 IIS 搭建 mercurial server
mercurial server 对于代码管理工具,更多的人可能对 Git 更熟悉一些(Git太火了).其实另外一款分布式代码管理工具也被广泛的使用,它就是 mercurial.当多人协作时最好能够通 ...
- Unity攻击敌人时产生泛白效果
Shader的代码如下,主要是将透明度为1的像素点输出为白色,其中_BeAttack表示角色被攻击的泛白状态 // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_M ...
- Hadoop版本的选择问题
自从2013年下半年开始,hadoop的版本开始了快速的更新换代,这和通信和互联网行业(ICT)的发展是密切相关的.随着移动网络的和宽带网络的覆盖以及数据传输速率的提升,线上的数据有了爆炸式的增长.这 ...