java基础25 线程的常用方法、线程安全问题、死锁现象
一、线程的常用方法
1、Thread(String name):初始化线程的名字
2、 setName(String name):设置线程的名字
3、 getName():返回线程的名字
4、 sleep(long millis):线程睡眠指定毫秒数.静态的方法.
5、 currentThread(): 返回当前线程对象
6、 getPriority():返回当前线程对象的优先级 默认优先级5
7、 setPriority(int newPriority):设置线程优先级 虽然设置了优先级,但是具体的实现取决于底层操作系统实现(最大优先级数是10,最小的是1,默认的是5)
8、其他几个方法,1.8、线程生命周期处 ..............
1.1、例1 Thread()、currentThread()
package com.zn.thread; /**
* @author DSHORE / 2018-5-7
*
*/
public class Demo2 extends Thread { public Demo2(String name) {
super(name);
}
@Override
public void run() {
//Thread.currentThread():返回当前线程对象
System.out.println("当前线程:"+Thread.currentThread());//运行结果:当前线程:Thread[二狗子线程,5,main];说明:当前线程是二狗子线程,优先级是5
System.out.println("this:"+this);//运行结果:this:Thread[二狗子线程,5,main] for(int i=;i<;i++){
System.out.println(Thread.currentThread().getName()+i);
}
}
public static void main(String[] args) {
Demo2 d = new Demo2("二狗子线程");
d.start(); System.out.println("当前线程:"+Thread.currentThread());//运行结果:当前线程:Thread[main,5,main] 说明:当前线程是主线程(main线程),优先级也是5 for(int j=;j<;j++){
System.out.println("主线程:"+j);
}
}
}
结果图
1.2、例2 setName()、getName()
1、setName():设置线程的名字
2、getName():获取线程的名字
package com.zn.thread; /**
* @author DSHORE / 2018-5-7
*
*/
public class Demo2 extends Thread { public Demo2(String name) {
super(name);
}
@Override
public void run() {//run()方法中的代码,都是自定义线程
for(int i=;i<;i++){
System.out.println(Thread.currentThread().getName()+i);//获取当前线程的名字
}
}
public static void main(String[] args) {
//创建一个线程对象
Demo2 d = new Demo2("二狗子线程");
d.setName("狗剩线程");//设置线程的名字
d.start(); Thread.currentThread().setName("隔壁老王线程");
for(int j=;j<;j++){
System.out.println(Thread.currentThread().getName()+j);
}
}
}
结果图 (狗剩线程 覆盖掉了 二狗子线程)
1.3、例3 sleep()
sleep():指定线程睡眠的时间(毫秒为单位)
package com.zn.thread; /**
* @author DSHORE / 2018-5-7
*
*/
public class Demo2 extends Thread { public Demo2(String name) {
super(name);
}
@Override
public void run() {
for(int i=;i<;i++){
System.out.println(Thread.currentThread().getName()+i);
try {
Thread.sleep();//休眠(暂停)100毫秒 1秒 = 1000毫秒
} catch (InterruptedException e) {//Thread类的run方法没有抛出异常类型,所以子类不能抛出异常
e.printStackTrace();//打印异常信息
}
}
}
public static void main(String[] args) {
//创建一个线程对象
Demo2 d = new Demo2("二狗子线程");
d.start(); Thread.currentThread().setName("隔壁老王线程");
for(int j=;j<;j++){
System.out.println(Thread.currentThread().getName()+j);
}
}
}
运行结果图 (其中一次的运行结果)
使用sleep()方法,睡了一下,几乎都被“隔壁老王全抢了线程”;二狗子线程在后面才执行
1.4、例4 getPriority()
getPriority():获取当前线程对象的优先级 默认优先级:5
setPriority():设置优先级数
package com.zn.thread; /**
* @author DSHORE / 2018-5-7
*
*/ public class Demo3 extends Thread {
@Override
public void run() {
Thread t = new Thread();//先创建线程对象,再去获取优先级数或设置优先级数
t.setPriority();//直接设置优先级
for(int i=;i<;i++){
System.out.println("当前线程:"+i+"\t"+t.getPriority());//getPriority():获取该线程对象的优先级数; 默认优先级是5
}
}
public static void main(String[] args) {
//创建一个线程对象
Demo3 d = new Demo3();
d.start(); Thread.currentThread().setName("隔壁老王线程");
for(int j=;j<;j++){
System.out.println(Thread.currentThread().getName()+j);
}
}
}
结果图
二、线程安全问题
2.1、java线程同步机制
方式一:同步代码块
synchronized(锁对象){
需要被同步的代码...
}
方式二:同步函数
修饰符 synchronized 返回值类型 函数名(参数类型 参数名){
}
public synchronized void add(int a) { //即:在普通函数上面加个 synchronized }
2.2、同步代码块要注意的问题
1.任意的一个对象都可以作为锁对象
2.在同步代码块中调用了sleep并不是释放锁对象.
3.只有真正存在线程安全问题是,才使用同步代码块,否则会降低效率
4.多线程操作的锁对象必须是唯一共享的,否则就无效了
实例1 (出现线程安全问题)
package com.zn.thread; /**
* @author DSHORE / 2018-5-8
*
* 模拟3个窗口同时在售20张票
*/ class Windows extends Thread{
static int num=;//票数 问题1 //得使用static共享num给三个线程(w1、w2、w3)一起使用 注:这是第二张结果图的程序,第一张int num 前面是没有static的。
public Windows(String name){
super(name);
}
@Override
public void run() {
while(true){//问题2 此处应该加个同步锁
if(num>){
System.out.println(Thread.currentThread().getName()+"售出第"+num+"票");
num--;
}else{
System.out.println("票已售罄");
break;
}
}
}
}
public class Demo3 {
public static void main(String[] args) {
//创建3个线程对象,模拟3个窗口
Windows w1=new Windows("窗口1");
Windows w2=new Windows("窗口2");
Windows w3=new Windows("窗口3");
//开启线程售票
w1.start();
w2.start();
w3.start();
}
}
运行结果图
两张图都出现了“三个窗口都有售出同一张票的情况”;即:出现了线程安全问题,解决该问题看例2
问题1:为什么出现了:售出60张票?
答:把num这个数据共享给三个线程对象使用,使用static
问题:出现线程安全问题
线程安全问题的解决方案:sun提供了同步机制让我们解决这类问题
实例2 (完美实例)
package com.zn.thread; /**
* @author DSHORE / 2018-5-8
*
* 模拟3个窗口同时在售20张票
*/
//同步代码块 例子
class Windows extends Thread{
static int num = ;//票数
//static Object o=new Object(); //多线程操作的锁对象必须是唯一共享
public Windows(String name){
super(name);
}
@Override
public void run() {
while(true){
//同步代码块
synchronized ("锁") { //synchronized (o){ } //任意的一个对象都可以作为锁对象
if(num>){
System.out.println(Thread.currentThread().getName()+"售出第"+num+"票");
try {
Thread.sleep();//睡眠100毫秒
} catch (InterruptedException e) {
e.printStackTrace();//打印异常信息
}
num--;
}else{
System.out.println("票已售罄");
break;
}
}
}
}
}
public class Demo3 {
public static void main(String[] args) {
//创建3个线程对象,模拟3个窗口
Windows w1=new Windows("窗口1");
Windows w2=new Windows("窗口2");
Windows w3=new Windows("窗口3");
//开启线程售票
w1.start();
w2.start();
w3.start();
}
}
运行结果图
2.3、出现安全问题的根本原因
1.存在两个或者两个以上的线程对象,而且线程之间共享一个资源.
2.有多个语句操作了共享资源
2.4、同步函数要注意的问题
1.如果是一个非静态的同步函数,锁对象是this对象(相当于全局变量)。如果是静态的同步函数的锁,对象是当前函数锁属的类的字节码文件(class对象)。
2.同步函数锁对象是固定的,不能由你来指定
推荐使用同步代码块
原因:
1.同步代码块锁对象由我们随意指定,方便控制;同步函数锁对象是固定的,不能由我们指定
2.同步代码块可以很方便的控制需要同步的范围,同步函数必须是整个函数的所有代码都被同步了.
//需求:两人同时取钱(卡+本子) //同步函数 例子
class BankThread extends Thread{
static int count=;
public BankThread(String name) {
super(name);
}
@Override
public void run() {
getMoney();
}
//同步函数
public static synchronized void getMoney(){ //静态的函数---->函数所属的类的字节码文件对象 BanckThread.class唯一的
while(true){
if(count>){
System.out.println(Thread.currentThread().getName()+"取走了10000,还剩"+(count-)+"元");
count=count-;
}else{
System.out.println("取完了..滚蛋");
break;
}
}
}
} public class Demo1 {
public static void main(String[] args) {
BankThread b=new BankThread("狗蛋");
BankThread b1=new BankThread("铁蛋");
b.start();
b1.start();
}
}
//问题:结果只有一个人能取到钱,另一个人始终没办法取到钱。原因:同步函数把所有代码都锁住了;这里应该用同步代码块
三、死锁现象
java同步机制解决了线程安全问题,但是也同时引发了死锁现象
3.1、死锁现象出现的根本原因
1.存在两个或者两个以上的线程.
2.存在两个或者两个以上共享资源.
3.2、死锁问题的解决方案
没有方案,只能尽量避免发生而已.
3.3、实例
package com.zn.thread; /**
* @author DSHORE / 2018-5-11
*
* java同步机制解决了线程安全问题,但是也同时引发了了死锁现象
*
* 需求:两个人抢着去打开电视机,但遥控器和电池是分开的,只有一个人同时拿到遥控器和电池才能打开电视机
*/
class DeadLock extends Thread{
public DeadLock(String name) {
super(name);
}
@Override
public void run() {
if("张三".equals(Thread.currentThread().getName())){
synchronized ("电池") {
System.out.println("张三拿到了电池,准备去拿遥控器");
synchronized ("遥控器") {
System.out.println("张三拿到了电池和遥控器,正在打开电视机 看电视");
}
}
}else if("李四".equals(Thread.currentThread().getName())){
synchronized ("遥控器") {
System.out.println("李四拿到了遥控器,准备去拿电池");
synchronized ("电池") {
System.out.println("李四拿到了遥控器和电池,正在打开电视机中");
}
}
}
}
}
public class Demo4 {
public static void main(String[] args) {
//创建线程对象
DeadLock d = new DeadLock("张三");
DeadLock d1 = new DeadLock("李四");
//开启线程
d.start();
d1.start();
}
}
运行结果图
原创作者:DSHORE 作者主页:http://www.cnblogs.com/dshore123/ 原文出自:http://www.cnblogs.com/dshore123/p/9004156.html 欢迎转载,转载务必说明出处。(如果本文对您有帮助,可以点击一下右下角的 推荐,或评论,谢谢!) |
java基础25 线程的常用方法、线程安全问题、死锁现象的更多相关文章
- Java基础图解,JVM,线程,Spring,TCP,SpringMVC等开发体系图解
Java基础图解,JVM,线程,Spring,TCP,SpringMVC等开发体系图解 1.Java虚拟机运行时数据区图 2. 堆的默认分配图 3.方法区结构图 4.对象的内存布局图 5.对象头的Ma ...
- Java基础加强之多线程篇(线程创建与终止、互斥、通信、本地变量)
线程创建与终止 线程创建 Thread类与Runnable接口的关系 public interface Runnable { public abstract void run(); } public ...
- JAVA基础知识之多线程——控制线程
join线程 在某个线程中调用其他线程的join()方法,就会使当前线程进入阻塞状态,直到被join线程执行完为止.join方法类似于wait, 通常会在主线程中调用别的线程的join方法,这样可以保 ...
- java基础九[网络与线程](阅读Head First Java记录)
网络socket连接 Java API的网络功能包(java.net)已经将底层的TCP连接等都封装好了,我们只需要通过Socket对象来建立客户端和服务器的连接,然后客户端能向服务器发送请求,并接收 ...
- JAVA基础知识系列---进程、线程安全
1 相关概念 1.1 临界区 保证在某一时刻只有一个线程能访问数据的简便方法,在任意时刻只允许一个线程对资源进行访问.如果有多个线程试图同时访问临界区,那么在有一个线程进入后,其他所有试图访问临界区的 ...
- java基础回顾(五)线程详解以及synchronized关键字
本文将从线程的使用方式.源码.synchronized关键字的使用方式和陷阱以及一些例子展开java线程和synchronized关键字的内容. 一.线程的概念 线程就是程序中单独顺序的流控制.线程本 ...
- Java基础知识(多线程和线程池)
新建状态: 一个新产生的线程从新状态开始了它的生命周期.它保持这个状态直到程序 start 这个线程. 运行状态:当一个新状态的线程被 start 以后,线程就变成可运行状态,一个线程在此状态下被认为 ...
- Java基础教程——多线程:创建线程
多线程 进程 每一个应用程序在运行时,都会产生至少一个进程(process). 进程是操作系统进行"资源分配和调度"的独立单位. Windows系统的"任务管理器&quo ...
- 毕向东JAVA基础25天教程目录
视频目录:day01-01-基本常识day01-02-Java的跨平台性day01-03-Java环境搭建(安装)day01-04-Java环境搭建(环境变量配置)day01-05-Java环境搭建( ...
随机推荐
- Windows + Ubuntu下JDK与adb/android环境变量配置完整教程
假设JDK和android sdk路径分别如下: D:\Program Files\Java\jdkD:\android-sdk 1.JDK环境变量配置JAVA_HOME=D:\Program Fil ...
- Andorid APK反逆向
Andorid APK反逆向解决方案---梆梆加固原理探寻http://blog.csdn.net/androidsecurity/article/details/8892635 Android AP ...
- c++ 宏多态 动态多态和静态多态(转载)
转载出处:通道 多态(polymorphism)一词最初来源于希腊语polumorphos,含义是具有多种形式或形态的情形.在程序设计领域,一个广泛认可的定义是“一种将不同的特殊行为和单个泛化记号相关 ...
- 论C语言中二级指针和二维数组之间的区别
刚开始学习C语言的时候,觉得一个数组可以定义一个一级指针去访问,想当然的就觉得可以定义一个二级指针去访问二维数组.很显然这是错误的. 我们来看看C语言的数组在内存中的存储方式. 实际上C语言中的数组, ...
- 题解【bzoj2653 middle】
Description 给你一个序列,每次询问给出四个数 \(a,b,c,d\),求所有区间 \([l,r]\) 满足 \(l \in [a,b], r \in [c,d]\) 的中位数的最大值.强制 ...
- 题解【bzoj2733 [HNOI2012]永无乡】
Descriprition 两种操作 把两个集合并起来 求一个集合中的第 \(k\) 大(的编号) \(n \leq 10^5\) Solution 平衡树的板子题之一 维护两个点连不连通直接并查集 ...
- Java基础-进程与线程之Thread类详解
Java基础-进程与线程之Thread类详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.进程与线程的区别 简而言之:一个程序运行后至少有一个进程,一个进程中可以包含多个线程 ...
- [转]windows下安装python MySQLdb及问题解决
转自 https://blog.csdn.net/ping523/article/details/54135228#commentBox 之前按照网络上搜罗的教程安装了python-mysql(1.2 ...
- IOS数组的排序和筛选
1.排序 [self.tableItems sortUsingComparator:^NSComparisonResult(GPBTeacherBrief* obj1, GPBTeacherBrief ...
- kibana多台服务部署
nohup /usr/share/kibana/bin/kibana -c /etc/kibana/kibana5602.yml & cp kibana.yml kibana5602.yml ...