网站首页 > java教程 正文
前言
程序:一组有序的指令集合
进程:执行中的程序
线程:是进程中“单一持续控制流程”
进程跟程序的区别:程序是一组指令的集合,它是静态的实体,没有执行的含义。而进程是一个动态的实体,有自己的生命周期。一般说来,一个进程肯定与一个程序相对应,并且只有 一个,但是一个程序可以有多个进程,或者一个进程都没有。除此之外,进程还有并发性和交往性。简单地说,进程是程序的一部分,程序运行的时候会产生进程。
进程与线程的区别:进程作为资源分配的单位,线程是调度和执行的单位
线程状态
新生状态、就绪状态、阻塞状态、运行状态、死亡状态
多线程的实现
Thread
PS:无法实现线程之间的数据共享
/**
* 通过 extends Thread
*/
public class MyThread extends Thread{
private final String name;
public MyThread(String name){
this.name = name;
}
@Override
public void run(){
for (int i = 0; i < 5; i++) {
System.out.println(this.name + ":" + i);
}
}
}
public static void main(String[] args) {
MyThread myThread = new MyThread("MyThread-0");
myThread.start();
}
Runnable
/**
* 通过 implements Runnable
*/
public class MyRunnable implements Runnable{
private final String name;
public MyRunnable(String name){
this.name = name;
}
@Override
public void run(){
for (int i = 0; i < 5; i++) {
System.out.println(this.name + ":" + i);
}
}
}
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable("MyRunnable-0");
new Thread(myRunnable).start();
}
Callable<V>
/**
* 通过 implements Callable<V>
*/
public class MyCallable implements Callable<String> {
private final String name;
public MyCallable(String name){
this.name = name;
}
@Override
public String call() throws Exception {
for (int i = 0; i < 5; i++) {
System.out.println(this.name + ":" + i);
}
return "执行完成";
}
}
public static void main(String[] args) {
MyCallable myCallable = new MyCallable("MyCallable-0");
new Thread(new FutureTask<String>(myCallable)).start();
}
线程池
public static void main(String[] args) {
MyThread myThread = new MyThread("MyThread-0");
MyRunnable myRunnable = new MyRunnable("MyRunnable-0");
MyCallable myCallable = new MyCallable("MyCallable-0");
//线程池
ExecutorService threadPool = Executors.newFixedThreadPool(10);
threadPool.submit(myThread);
threadPool.submit(myRunnable);
threadPool.submit(myCallable);
//关闭线程池
threadPool.shutdown();
}
并发安全
synchronized
使用synchronized关键字对线程加锁,在有线程获取该内存锁后,其它线程无法访问该内存,从而实现JAVA中简单的同步、互斥操作。
同步代码块
synchronized(Obj){//obj叫做同步监听器,只能是引用类型
}
同步方法
public synchronized void fun(){//同步方法中,默认使用this当前对象作为同步对象
}
Lock
从jdk1.5之后,java提供了另外一种方式来实现同步访问,那就是Lock。
//可重入锁
Lock lock = new ReentrantLock();
//加锁
lock.lock();
try{
//并发处理逻辑...
}catch(Exception ex){
}finally{
//释放锁
lock.unlock();
}
老公、老婆同时取钱例子:
/**
* 银行账户
*/
public class Account {
//余额
private int balance = 1000;
public Account() {
}
public Account(int balance) {
this.balance = balance;
}
public int getBalance() {
return balance;
}
public void setBalance(int balance) {
this.balance = balance;
}
}
使用synchronized
/**
* 通过 implements Runnable
*/
public class MyRunnable implements Runnable{
private final String name;
private final Account account;
public MyRunnable(Account account,String name){
this.account = account;
this.name = name;
}
@Override
public void run(){
for (int i = 0; i < 5; i++) {
//加锁,锁的是银行账户对象
synchronized (account) {
//余额大于200
if (account.getBalance() >= 200) {
//模拟耗时
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
//取钱成功
account.setBalance(account.getBalance() - 200);
System.out.println(this.name + "取走了200元,当前余额为:" + account.getBalance());
} else {
System.out.println(this.name + "取钱失败,余额不足");
}
}
}
}
}
使用Lock
/**
* 通过 implements Runnable
*/
public class MyRunnable implements Runnable{
private final String name;
private final Account account;
//可重入锁
private static final Lock lock = new ReentrantLock();
public MyRunnable(Account account,String name){
this.account = account;
this.name = name;
}
@Override
public void run(){
for (int i = 0; i < 5; i++) {
//加锁
lock.lock();
try{
//余额大于200
if (account.getBalance() >= 200) {
//模拟耗时
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
//取钱成功
account.setBalance(account.getBalance() - 200);
System.out.println(this.name + "取走了200元,当前余额为:" + account.getBalance());
} else {
System.out.println(this.name + "取钱失败,余额不足");
}
}catch(Exception e){
e.printStackTrace();
}finally{
//释放锁
lock.unlock();
}
}
}
}
测试
public static void main(String[] args) {
//初始化银行账户
Account account = new Account();
//老公、老婆同时取钱
new Thread(new MyRunnable(account,"老公")).start();
new Thread(new MyRunnable(account,"老婆")).start();
}
如果不加锁,就会出现并发安全问题
死锁
死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程
死锁的发生必须具备以下四个必要条件。
1)互斥条件:指进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。如果此时还有其它进程请求资源,则请求者只能等待,直至占有资源的进程用毕释放。
2)请求和保持条件:指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放。
3)不剥夺条件:指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。
4)环路等待条件:指在发生死锁时,必然存在一个进程——资源的环形链,即进程集合{P0,P1,P2,···,Pn}中的P0正在等待一个P1占用的资源;P1正在等待P2占用的资源,……,Pn正在等待已被P0占用的资源。
后记
Thread.sleep():使线程进入阻塞状态,会释放CPU资源但不会释放对象锁的控制
Object.wait():当前线程必须拥有此对象监视器。该线程释放对此监视器的所有权(释放synchronize锁)并等待,直到其他线程通过调用 notify 方法,或 notifyAll 方法通知在此对象的监视器上等待的线程醒来。然后该线程将等到重新获得对监视器的所有权后才能继续执行。
Thread.sleep()与Object.wait()二者都可以暂停当前线程,释放CPU控制权,主要的区别在于Object.wait()在释放CPU同时,释放了对象锁的控制
版权声明
作者:huanzi-qch
出处:https://www.cnblogs.com/huanzi-qch
若标题中有“转载”字样,则本文版权归原作者所有。若无转载字样,本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利.
猜你喜欢
- 2024-10-13 GitHub热点推荐!85W字并发编程图册(全彩版),竟是出自阿里
- 2024-10-13 「不得不看」Java并发编程一(java并发编程之美)
- 2024-10-13 深入理解java并发编程、并发编程相关概念基础篇
- 2024-10-13 Java 高并发编程详解:多线程与架构设计首稿写作完成
- 2024-10-13 Java面试专题——并发编程(juc并发编程面试题)
- 2024-10-13 Java编程——如何实现高效的并发控制
- 2024-10-13 Java线程与并发编程实践:深入理解volatile和final变量
- 2024-10-13 简单理解JAVA并发编程及高并发(java并发编程实战和并发编程的艺术)
- 2024-10-13 高并发编程系列:全面剖析Java并发编程之AQS的核心实现
- 2024-10-13 Java 多线程并发编程(关于java多线程并发控制机制)
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)