一.普通对象,线程对象,线程
- 普通对象:针对于线程对象而言的。到处可见普通对象,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 "";
}
}
}
分享到:
相关推荐
正是由于这种操作系统的出现才有了多线程这个概念。我们使用的windows,linux就属于此列。什么是分时操作系统呢,通俗一点与就是可以同一时间执行多个程序的操作系统,在自己的电脑上面,你是不是一边听歌,一边聊天...
本文中我们从 5 个方面总结出 Linux 多线程编程上的问题,并分别引出相关改善的开发经验,用以避免这些的陷阱。我们希望这些经验可以帮助读者们能更好更快的熟悉 Linux 平台的多线程编程。 我们假设读者都已经很...
1. 多线程的基本概念 每一个正在执行的程序都是一个进程,资源只有一块,所以在同一时间段会有多个程序同时执行,但是在一个时间点上,只能由一个程序执行,多线程是在一个进程的基础之上的进一步划分,因为进程的...
14. 线程的定义:线程是进程内的一个实体,是处理机调度的基本单位,是程序内部一个单一的顺序控 制流。 15. 引入进程的目的:是为了使多个程序并发执行,提高资源利用率和系统吞吐量。 16. 引入线程的目的:是为了...
本章的学习目标 了解进程和线程的基本概念和区别 掌握创建线程的两种方法 掌握线程同步的概念和方法 了解线程的优先级 掌握线程间通信的方法 第3页 Java程序设计案例教程-第8章-多线程编程全文共36页,当前为第3页...
个人的小总结,适合初学者,包含了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中还包括继承、多态等面向对象的基本概念。 异常处理:Java中的异常处理是一种处理错误和异常情况的方法。Java中的异常处理通过try-catch语句实现,可以捕捉和处理程序中出现的异常情况。 文件读写:Java中的...
进程就是一个应用程序在处理机上的一次执行过程,它是一个动态的概念,而线程是进程中的一部分,进程包含多个线程在运行。 线程是指进程内的一个执行单元,也是进程内的可调度实体. 与进程的区别: (1)地址空间:...
十二、 多线程★★★★ 39 为什么要使用多线程 39 创建线程和启动 39 线程的生命周期 44 线程管理 45 线程同步 49 线程通信 52 线程池 58 死锁 64 线程相关类 65 十三、 同步★★★★★ 67 十四、 Lock接口 70 十五...
1、基本概念 IO多路复用是指内核一旦发现进程指定的一个或者多个IO条件准备读取,它就通知该进程。IO多路复用适用如下场合: (1)当客户处理多个描述字时(一般是交互式输入和网络套接口),必须使用I/O复用。 (2...
基本概念 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 ...
基本内容包括 1)信号 2)多线程同步与互斥 3)进程管理与通信 4)文件与文件夹 5)I/O操作 我就是在他的基础山扩展学习,起初什么也不懂.这是他人的总结,我们要感谢他们的辛苦工作。
多线程并发访问,同步控制 线程间通信,等待/通知机制 锁锁机制,API详解 Fork/Join 框架机制详解 Executor线程池框架简介 面向对象 泛型机制与反射原理 Proxy动态代理机制详解 从整体上观察对象 网络开发 Servlet...
面向对象计算始于这个基本概念,即现实世界可以被描绘成一系列完全自治、封装的对象,这些对象通过一个受保护的接口访问其他对象。 4. 多态性: 多态性是指允许不同类的对象对同一消息作出响应。多态性包括参数化多...
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篇 ...
Java IO流学习总结 Java流操作有关的类或接口: Java流类图结构: ...流的概念和作用 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。... 可以用于多线程下载或多个线程同时写数据到文件。