一.普通对象,线程对象,线程
- 普通对象:针对于线程对象而言的。到处可见普通对象,Person p = new Person();一个无头无脑的人就是一个普通对象。
- 线程对象:线程类的实例对象。我自己定义了一个线程类public class CheckThread extends Thread{...},然后CheckThread ct = new CheckThread(),ct就是线程对象。
- 线程:代码的一次执行过程。
- 从概念层面讲,普通对象和线程对象是实实在在的东西,线程是虚的东西。线程好比一条细线。把普通对象和线程对象上的方法串起来执行,得到想要的结果而已。
- 从内存层面讲,对象就是一块内存地址,里面有数据和运行方法。而线程就是这些方法的一次执行路径。
- 唯一觉得线程对象和线程有点关系的地方:线程对象定义了线程的一个入口(线程对象的run方法),就好像main方法开启了主线程的一个入口一样。
二.锁和同步
- 锁是针对对象或者类而言的。Java中每个对象都有一个内置锁。
- 同步的表现形式为synchronized方法或者synchronized代码块,作用为同一时刻,只能有一个线程调用此方法或代码块。当程序运行到synchronized同步方法或代码块时锁才起作用。
- 对象锁:
- 线程1调用synchronized
getX()方法时,有幸获得对象锁,会把对象锁带在自己身上,此时线程2想进入synchronized
getX()方法或者synchronized
getY()方法等任何非静态同步方法时,看到synchronized就需要对象锁,由于对象锁被线程1占有者,所以线程2只能等待。
- 线
程1调用getX()的synchronized代码块时,有幸获得对象锁,会把对象锁带在自己身上,此时线程2可以进入getX()或者getY()方
法,但进入后什么时候发现synchronized代码块,就什么时候需要对象锁,由于对象锁被线程1占有者,所以线程2只能等待。
- 如果一个类有有两个实例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;
}
}
- 类锁:和对象锁差不多的
- 线程3调用synchronized static setName()方法时,有幸获得类锁,会把类锁带在自己身上,此时线程4想进入synchronized static setName()方法或者synchronized
static setAge()方法等任何静态同步方法时,看到synchronized就需要类锁,由于类锁被线程3占有者,所以线程4只能等待。
- 线
程3调用static setName()的synchronized代码块时,有幸获得类锁,会把类锁带在自己身上,此时线程4可以进入setName()或者setAge()方法等任何静态同步方法时,但进入后什么时候发现synchronized代码块,就什么时候需要类锁,由于类锁被线程3占有者,所以线程4只能等待。
- 区别于对象的是,类的静态方法是有一份,多个线程都想调用此同步静态方法时,同一时刻肯定只能有一个线程能调用。
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;
}
}
- 线程1对静态同步方法的调用用到类锁,线程3对非静态同步方法的调用用到对象锁,它们之间不会产生阻塞。
- 一个对象可以同步方法和非同步方法同时存在,线程对同步方法的调用需要获得锁,对非同步方法的调用不需要。
- 总结线程一看到synchronized方法或代码块时三步曲,每个线程来的时候你都这么想一下,就理清头绪了。
- 线程要搞清楚要得到什么样的锁才能进入这个方法或代码块。
- 这把锁现在是什么状态。
- 线程拿到了这把锁后一起把锁带入方法或代码块里,直到方法和代码块区域执行完后释放锁。
三.测试用例
引用下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 "";
}
}
}
分享到:
相关推荐
### Java多线程编程大总结 #### 一、Java多线程编程的演进与重要性 Java多线程编程自Java 5之后经历了显著的革新与扩展,引入了强大的并发包,极大地增强了多线程编程的能力。在Java 5之前,多线程的支持较为薄弱...
【JAVA多线程总结】 Java 多线程是Java编程中的关键特性,它允许程序同时执行多个任务,提高系统的效率和响应性。本篇总结涵盖了Java多线程的基础概念、创建与启动、线程调度、同步与协作以及新特性。 **一、Java...
【Windows多线程总结】 Windows操作系统提供了一套完整的API来支持多线程编程,使得开发者可以在同一进程中同时执行多个线程,实现并发处理任务。本文将深入探讨Windows多线程编程的基本概念、线程同步、线程池以及...
在IT行业中,网络编程是至关重要的领域,而HTTP协议、多线程技术以及远程方法调用(RMI)是其中的三大核心概念。本实验旨在通过编写简单的HTTP 1.0客户端/服务器程序、多线程Web服务器以及RMI程序,帮助你深入理解...
MFC 多线程完整总结及示例代码 ...多线程编程是 MFC 编程中的一种重要技术,通过了解多线程的基本概念、多线程编程的重要性、Win32 API 函数的使用和 MFC 类库的应用,可以更好地掌握多线程编程。
理解线程的基本概念、状态以及如何管理和控制线程对于编写高效可靠的多线程应用程序至关重要。通过对同步机制、线程控制技术以及线程间的通信方式的掌握,开发者能够更好地利用多线程的优势解决实际问题。
Java多线程是Java编程语言中一个非常重要的概念,它允许开发者在一个程序中创建多个执行线程并行运行,以提高程序的执行效率和响应速度。在Java中,线程的生命周期包含五个基本状态,分别是新建状态(New)、就绪...
本文从多线程的基础概念出发,深入探讨了Java中多线程的实现机制及线程安全问题,并介绍了几种常见的设计模式(包括单例模式、工厂模式和适配器模式),这些模式有助于解决多线程环境下的常见问题。通过对这些知识点...
Java多线程是Java编程中的核心概念,它允许程序同时执行多个任务,提高了程序的效率和响应速度。本文将深入探讨Java多线程的相关知识点,包括线程的创建、线程的状态、同步机制以及线程安全问题。 1. **线程的创建*...
线程优先级、抢占式调度等概念影响着多线程程序的性能。 5. **线程安全**:当多个线程访问同一资源时,需要确保代码是线程安全的,即不会因并发执行而产生错误。这通常涉及到对临界区的保护,避免竞态条件的发生。 ...
通过理解多线程的基本概念,掌握易语言中的线程创建和管理方法,以及注意线程安全和同步,你可以编写出高效且稳定的多线程程序。在实际开发中,不断实践和优化,将是提升多线程编程能力的关键。
在本实验中,我们将深入了解线程与进程的基本概念、它们之间的区别与联系,并掌握多线程技术在Java中的应用方法。具体包括以下几点: 1. **线程与进程的概念、区别与联系**:线程是进程中的执行单元,一个进程可以...
本文将对多线程进行深入总结,主要涵盖线程的基本概念、使用多线程的原因以及在iPhone平台上创建和管理线程的几种方法。 一、线程简介 线程是操作系统分配CPU时间的基本单位,它可以看作是程序执行流的最小单元。...
总的来说,多线程基础编程涵盖了从基本概念到实际应用的广泛内容,理解并掌握这些知识点对于编写高效、稳定的并发程序至关重要。通过思维导图的方式,我们可以更好地组织和记忆这些复杂的概念,以便在实践中灵活运用...
### CoreJava多线程学习总结 #### 一、基本概念 多线程是现代软件开发中非常重要的一个概念,尤其在Java这样的高级编程语言中,它使得程序能够更高效地利用计算机资源,实现并发处理任务。为了更好地理解CoreJava...