`
zy19982004
  • 浏览: 654377 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
博客专栏
F6f66edc-1c1a-3859-b76b-a22e740b7aa7
Hadoop学习
浏览量:249886
社区版块
存档分类
最新评论

多线程总结一:基本概念

 
阅读更多

一.普通对象,线程对象,线程

  1. 普通对象:针对于线程对象而言的。到处可见普通对象,Person p = new Person();一个无头无脑的人就是一个普通对象。
  2. 线程对象:线程类的实例对象。我自己定义了一个线程类public class CheckThread extends Thread{...},然后CheckThread ct = new CheckThread(),ct就是线程对象。
  3. 线程:代码的一次执行过程。
  4. 从概念层面讲,普通对象和线程对象是实实在在的东西,线程是虚的东西。线程好比一条细线。把普通对象和线程对象上的方法串起来执行,得到想要的结果而已。
  5. 从内存层面讲,对象就是一块内存地址,里面有数据和运行方法。而线程就是这些方法的一次执行路径。
  6. 唯一觉得线程对象和线程有点关系的地方:线程对象定义了线程的一个入口(线程对象的run方法),就好像main方法开启了主线程的一个入口一样。

二.锁和同步

  1. 锁是针对对象或者类而言的。Java中每个对象都有一个内置锁。
  2. 同步的表现形式为synchronized方法或者synchronized代码块,作用为同一时刻,只能有一个线程调用此方法或代码块。当程序运行到synchronized同步方法或代码块时锁才起作用。
  3. 对象锁:
    1. 线程1调用synchronized getX()方法时,有幸获得对象锁,会把对象锁带在自己身上,此时线程2想进入synchronized getX()方法或者synchronized getY()方法等任何非静态同步方法时,看到synchronized就需要对象锁,由于对象锁被线程1占有者,所以线程2只能等待。
    2. 线 程1调用getX()的synchronized代码块时,有幸获得对象锁,会把对象锁带在自己身上,此时线程2可以进入getX()或者getY()方 法,但进入后什么时候发现synchronized代码块,就什么时候需要对象锁,由于对象锁被线程1占有者,所以线程2只能等待。
    3. 如果一个类有有两个实例A和B,线程1调用对象A的synchronized getX()方法时,用到对象A的锁,线程2调用对象B的synchronized getX()方法时,用到对象B的锁,两个锁不一样,所以两个线程可以同时进行。
      public synchronized int getX() {
              return x++;
      }
      public synchronized int getY() {
              return y++;
      }
      public int getX() {
              synchronized (this) {
                  return x;
           }
       }
      public int getY() {
              synchronized (this) {
                  return y;
           }
       }
  4. 类锁:和对象锁差不多的
    1. 线程3调用synchronized static setName()方法时,有幸获得类锁,会把类锁带在自己身上,此时线程4想进入synchronized static setName()方法或者synchronized static setAge()方法等任何静态同步方法时,看到synchronized就需要类锁,由于类锁被线程3占有者,所以线程4只能等待。
    2. 线 程3调用static setName()的synchronized代码块时,有幸获得类锁,会把类锁带在自己身上,此时线程4可以进入setName()或者setAge()方法等任何静态同步方法时,但进入后什么时候发现synchronized代码块,就什么时候需要类锁,由于类锁被线程3占有者,所以线程4只能等待。
    3. 区别于对象的是,类的静态方法是有一份,多个线程都想调用此同步静态方法时,同一时刻肯定只能有一个线程能调用。
      public static synchronized int setName(String name){
            Xxx.name = name;
      }
      public static synchronized int setAge(String age){
            Xxx.age= age;
      }
      
      public static int setName(String name){
            synchronized(Xxx.class){
                  Xxx.name = name;
            }
      }
      public static int setAge(String age){
            synchronized(Xxx.class){
                  Xxx.age= age;
            }
      }
       
  5. 线程1对静态同步方法的调用用到类锁,线程3对非静态同步方法的调用用到对象锁,它们之间不会产生阻塞。
  6. 一个对象可以同步方法和非同步方法同时存在,线程对同步方法的调用需要获得锁,对非同步方法的调用不需要。
  7. 总结线程一看到synchronized方法或代码块时三步曲,每个线程来的时候你都这么想一下,就理清头绪了。
    1. 线程要搞清楚要得到什么样的锁才能进入这个方法或代码块。
    2. 这把锁现在是什么状态。
    3. 线程拿到了这把锁后一起把锁带入方法或代码块里,直到方法和代码块区域执行完后释放锁。

三.测试用例

     引用下greatwqs 的例子,1234线程组合式的运行其中两个,能证明上面说的每一点。

package com.zzy.Thread;
public class ThreadTest {
	public static void main(String[] args) {
		final MyObject obj = new MyObject();
		final MyObject obj2 = new MyObject();
		//线程1
		Runnable r1 = new Runnable(){
			public void run(){
				obj.getName(1);
			}
		};
		Thread t1 = new Thread(r1);
		t1.start();
		//线程2
		Runnable r2 = new Runnable(){
			public void run(){
				obj.getAge(2);
			}
		};
		Thread t2 = new Thread(r2);
		t2.start();
		//线程3
		Runnable r3 = new Runnable(){
			public void run(){
				MyObject.getNameStatic(3);
			}
		};
		Thread t3 = new Thread(r3);
		t3.start();
		
		//线程4
		Runnable r4 = new Runnable(){
			public void run(){
				obj2.getName(4);
			}
		};
		Thread t4 = new Thread(r4);
		t4.start();
	}
}
class MyObject {
	public String getName(int i) {
		synchronized (this) {
			try {
				System.out.println("线程" + i + ":getName sleep 10 secs start");
				Thread.sleep(1000 * 10);
				System.out.println("线程" + i + ":getName sleep 10 secs end");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			return "";
		}
	}
	public String getAge(int i) {
		synchronized (this) {
			try {
				System.out.println("线程" + i + ":getAge sleep 10 secs start");
				Thread.sleep(1000 * 10);
				System.out.println("线程" + i + ":getAge sleep 10 secs end");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			return "";
		}
	}
	
	public static String getNameStatic(int i) {
		synchronized (MyObject.class) {
			try {
				System.out.println("线程" + i + ":getNameStatic sleep 10 secs start");
				Thread.sleep(1000 * 10);
				System.out.println("线程" + i + ":getNameStatic sleep 10 secs end");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			return "";
		}
	}
}
 

 

5
7
分享到:
评论
7 楼 zy19982004 2012-08-10  
greatwqs 写道
lemon_1227 写道
我表示你解释的有问题。

应该是下面的解释:
1.public static synchronized int setName(String name){   
2.      Xxx.name = name;   
3.}   
这个表示该方法被Lock了,同一时刻,只能有一个线程占用该资源。
  
5.public static int setName(String name){   
6.      synchronized(Xxx.class){   // 这个表示该类的所有synchronized 方法被lock 了
7.            Xxx.name = name;   
8.      }   
9.}  




对象锁, 也符合上面解释.
package com.greatwqs.test.thread;
public class ThreadTest {
	public static void main(String[] args) {
		final MyObject obj = new MyObject();
		Runnable r1 = new Runnable(){
			public void run(){
				obj.getName();
			}
		};
		Thread t1 = new Thread(r1);
		t1.start();
		Runnable r2 = new Runnable(){
			public void run(){
				obj.getAge();
			}
		};
		Thread t2 = new Thread(r2);
		t2.start();
	}
}
class MyObject {
	public String getName() {
		synchronized (this) {
			try {
				System.out.println("getName sleep 10 secs start");
				Thread.sleep(1000 * 10);
				System.out.println("getName sleep 10 secs end");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			return "";
		}
	}
	public String getAge() {
		synchronized (this) {
			try {
				System.out.println("getAge sleep 10 secs start");
				Thread.sleep(1000 * 10);
				System.out.println("getAge sleep 10 secs end");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			return "";
		}
	}
}



例子不错
运行结果应该是:
getName sleep 10 secs start        线程1启动,获得对象obj锁 (其实线程2这个时候也启动了) 
10s后                              睡眠期间不释放锁
getName sleep 10 secs end          睡眠结束 打印这句话后就释放对象obj锁
立刻
getAge sleep 10 secs start         锁此里面的线程2终于获得了对象obj锁
10s后                              睡眠期间不释放锁
getAge sleep 10 secs end           睡眠结束 打印这句话后就释放对象obj锁



6 楼 greatwqs 2012-08-10  
lemon_1227 写道
我表示你解释的有问题。

应该是下面的解释:
1.public static synchronized int setName(String name){   
2.      Xxx.name = name;   
3.}   
这个表示该方法被Lock了,同一时刻,只能有一个线程占用该资源。
  
5.public static int setName(String name){   
6.      synchronized(Xxx.class){   // 这个表示该类的所有synchronized 方法被lock 了
7.            Xxx.name = name;   
8.      }   
9.}  




对象锁, 也符合上面解释.
package com.greatwqs.test.thread;
public class ThreadTest {
	public static void main(String[] args) {
		final MyObject obj = new MyObject();
		Runnable r1 = new Runnable(){
			public void run(){
				obj.getName();
			}
		};
		Thread t1 = new Thread(r1);
		t1.start();
		Runnable r2 = new Runnable(){
			public void run(){
				obj.getAge();
			}
		};
		Thread t2 = new Thread(r2);
		t2.start();
	}
}
class MyObject {
	public String getName() {
		synchronized (this) {
			try {
				System.out.println("getName sleep 10 secs start");
				Thread.sleep(1000 * 10);
				System.out.println("getName sleep 10 secs end");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			return "";
		}
	}
	public String getAge() {
		synchronized (this) {
			try {
				System.out.println("getAge sleep 10 secs start");
				Thread.sleep(1000 * 10);
				System.out.println("getAge sleep 10 secs end");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			return "";
		}
	}
}

5 楼 zy19982004 2012-08-10  
lemon_1227 写道
我表示你解释的有问题。

应该是下面的解释:
1.public static synchronized int setName(String name){   
2.      Xxx.name = name;   
3.}   
这个表示该方法被Lock了,同一时刻,只能有一个线程占用该资源。
此方法被lock了,其他 static synchronized 也是被lock的。
这个和下面的“该类的所有synchronized 方法被lock 了”是一样的效果。
  
5.public static int setName(String name){   
6.      synchronized(Xxx.class){   // 这个表示该类的所有synchronized 方法被lock 了
7.            Xxx.name = name;   
8.      }   
9.}  





他们最终的效果还是一样的。
4 楼 kuchaguangjie 2012-08-10  
去看看 <java specification 7> 最后关于 并发 的那章,
讲的比较清晰,
3 楼 814687491 2012-08-09  
leechau 写道
lemon_1227的意思是说,假设Xxx类还有一个static setAge方法,
synchronized(Xxx.class){
意味着某一时刻只能有一个线程访问setName或者setAge中的一个方法?

肯定啥。类同步的时候,其它线程也无法访问该类其它同步方法的,你是对象锁嘛
2 楼 leechau 2012-08-09  
lemon_1227的意思是说,假设Xxx类还有一个static setAge方法,
synchronized(Xxx.class){
意味着某一时刻只能有一个线程访问setName或者setAge中的一个方法?
1 楼 lemon_1227 2012-08-09  
我表示你解释的有问题。

应该是下面的解释:
1.public static synchronized int setName(String name){   
2.      Xxx.name = name;   
3.}   
这个表示该方法被Lock了,同一时刻,只能有一个线程占用该资源。
  
5.public static int setName(String name){   
6.      synchronized(Xxx.class){   // 这个表示该类的所有synchronized 方法被lock 了
7.            Xxx.name = name;   
8.      }   
9.}  



相关推荐

    Java线程总结教程

    正是由于这种操作系统的出现才有了多线程这个概念。我们使用的windows,linux就属于此列。什么是分时操作系统呢,通俗一点与就是可以同一时间执行多个程序的操作系统,在自己的电脑上面,你是不是一边听歌,一边聊天...

    linux多线程开发区别与window

    本文中我们从 5 个方面总结出 Linux 多线程编程上的问题,并分别引出相关改善的开发经验,用以避免这些的陷阱。我们希望这些经验可以帮助读者们能更好更快的熟悉 Linux 平台的多线程编程。 我们假设读者都已经很...

    Java-学习多线程总结上

    1. 多线程的基本概念 每一个正在执行的程序都是一个进程,资源只有一块,所以在同一时间段会有多个程序同时执行,但是在一个时间点上,只能由一个程序执行,多线程是在一个进程的基础之上的进一步划分,因为进程的...

    操作系统概念归纳总结

    14. 线程的定义:线程是进程内的一个实体,是处理机调度的基本单位,是程序内部一个单一的顺序控 制流。 15. 引入进程的目的:是为了使多个程序并发执行,提高资源利用率和系统吞吐量。 16. 引入线程的目的:是为了...

    Java程序设计案例教程-第8章-多线程编程.pptx

    本章的学习目标 了解进程和线程的基本概念和区别 掌握创建线程的两种方法 掌握线程同步的概念和方法 了解线程的优先级 掌握线程间通信的方法 第3页 Java程序设计案例教程-第8章-多线程编程全文共36页,当前为第3页...

    Java多线程简单Demo

    个人的小总结,适合初学者,包含了java多线程的基本概念,再配上简单的demo,相信初学者学习完对多线程能有较清晰的认识

    一篇文章快速了解多线程

    实现多线程2.1 继承Thread2.2 实现Runnable接口2.3 实现Callable接⼝2.4 线程池3. Thread类3.1 构造方法3.2 常用方法3.3 线程优先级4. 线程的生命周期5. 线程同步5.1 synchronized锁5.1.1 同步代码块5.1.2同步方法...

    java各知识点详细总结.docx

    Java中还包括继承、多态等面向对象的基本概念。 异常处理:Java中的异常处理是一种处理错误和异常情况的方法。Java中的异常处理通过try-catch语句实现,可以捕捉和处理程序中出现的异常情况。 文件读写:Java中的...

    iOS 多线程总结之GCD的使用详解

    进程就是一个应用程序在处理机上的一次执行过程,它是一个动态的概念,而线程是进程中的一部分,进程包含多个线程在运行。 线程是指进程内的一个执行单元,也是进程内的可调度实体. 与进程的区别: (1)地址空间:...

    Java基础知识点总结.docx

    十二、 多线程★★★★ 39 为什么要使用多线程 39 创建线程和启动 39 线程的生命周期 44 线程管理 45 线程同步 49 线程通信 52 线程池 58 死锁 64 线程相关类 65 十三、 同步★★★★★ 67 十四、 Lock接口 70 十五...

    IO多路复用之select全面总结(必看篇)

    1、基本概念 IO多路复用是指内核一旦发现进程指定的一个或者多个IO条件准备读取,它就通知该进程。IO多路复用适用如下场合: (1)当客户处理多个描述字时(一般是交互式输入和网络套接口),必须使用I/O复用。 (2...

    java8源码-concurrency:java并发总结

    基本概念 1.1 CPU与线程的关系 1.2 线程与进程的区别和关系 1.3 吞吐量 1.4 线程安全 1.5 线程声明周期 1.6 守护线程 1.7 Java内存模型 1.8 可重入 1.9 偏向锁、轻量级锁、重量级锁 1.10 锁的公平性 1.11 线程组 2 ...

    Linux 初级学习的基本概念和资料

    基本内容包括 1)信号 2)多线程同步与互斥 3)进程管理与通信 4)文件与文件夹 5)I/O操作 我就是在他的基础山扩展学习,起初什么也不懂.这是他人的总结,我们要感谢他们的辛苦工作。

    免费超全面的Java基础类型,容器,并发,IO流,面向对象,Web编程等代码总结

    多线程并发访问,同步控制 线程间通信,等待/通知机制 锁锁机制,API详解 Fork/Join 框架机制详解 Executor线程池框架简介 面向对象 泛型机制与反射原理 Proxy动态代理机制详解 从整体上观察对象 网络开发 Servlet...

    java 面试题 总结

    面向对象计算始于这个基本概念,即现实世界可以被描绘成一系列完全自治、封装的对象,这些对象通过一个受保护的接口访问其他对象。 4. 多态性: 多态性是指允许不同类的对象对同一消息作出响应。多态性包括参数化多...

    java 编程入门思考

    1.9 多线程 1.10 永久性 1.11 Java和因特网 1.11.1 什么是Web? 1.11.2 客户端编程 1.11.3 服务器端编程 1.11.4 一个独立的领域:应用程序 1.12 分析和设计 1.12.1 不要迷失 1.12.2 阶段0:拟出一个计划 1.12.3 阶段...

    系统架构师考试知识点总结

    微内核结构由一个简单的硬件抽象层和一组比较关键的原语(仅仅为建立系统必须的部分,包括线程管理、地址空间和进程间通信)或系统调用组成。 微内核的目标将系统服务的实现和系统的基本操作规则分离开来

    Java入门1·2·3:一个老鸟的Java学习心得.PART3(共3个)

    对Java语言的每个语法都提供了一个或多个例程讲解 大量使用流程图表示程序的执行过程,使用结构图表示程序的内部状态 每章最后都给出了典型的练习题,让读者及时练习,巩固提高,并提供了参考答案 目录 第1篇 ...

    Java之IO流学习总结

    Java IO流学习总结 Java流操作有关的类或接口: Java流类图结构: ...流的概念和作用 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。... 可以用于多线程下载或多个线程同时写数据到文件。

Global site tag (gtag.js) - Google Analytics