java多线程并发安全问题,java开发安全问题
1.多线程并发操作的安全问题是什么?当多个线程并发操作一个数据时,线程操作的时间不可控,可能导致操作数据的过程不按照程序设计的执行顺序运行,导致操作后数据混乱,严重时甚至导致系统瘫痪。
2.用synchronized修饰的方法当一个方法用synchronized修饰时,该方法就变成了“synchronized方法”。如果多个线程不能同时进入方法的内容运行,就必须按顺序一个一个运行,这样才能避免并发安全问题。
案例:抢豆豆事件(这样豆豆剩余量不能为负)公开课SyncDemo {
公共静态void main(String[] args) {
Table table=新表();
线程t1=新线程(){
公共无效运行(){
while(true){
int n=table . get bean();
Thread.yield()。
system . out . println(thread . current thread()。getname(),豌豆还剩 n );
}
}
};
线程t2=新线程(){
公共无效运行(){
while(true){
int n=table . get bean();
Thread.yield()。
system . out . println(thread . current thread()。getname(),豌豆还剩 n );
}
}
};
t1 . start();
T2 . start();
}
}
类别表{
private int bean=10
public synchronized int getBean(){
if(bean==0){
抛出new RuntimeException(没有豌豆);
}
/*
* yield()会使线程从运行状态转换到就绪状态,但可能没有效果。
*暂停当前正在执行的线程对象(放弃当前拥有的cpu资源)当其工作时,
*并执行其他线程。
*/
线程。收益率();//模拟切换线程
返回bean-;
}
}运行结果:
当剩余豆量为0时,程序抛出异常。如果锁没有锁,有一定几率程序会跳过豆豆为0的条件继续运行。
3.同步模块1。有效缩小同步范围,可以在保证并发安全的前提下,尽可能提高效率。
2.同步块
同步(同步监视器){
//需要同步运行的代码片段
}3.同步块可以更加灵活准确地锁定需要同步的代码片段,可以有效缩小同步范围,提高并发效率。但是,应该注意的是,只有多个线程才能看到同步监视器对象是同一个对象。
案例:模拟商场买衣服公开课Syncdemo2 {
公共静态void main(String[] args) {
Shop Shop=new Shop();
线程t1=新线程(){
公共无效运行(){
shop . buy();
}
};
线程t2=新线程(){
公共无效运行(){
shop . buy();
}
};
t1 . start();
T2 . start();
}
}
班级商店{
公共void buy(){
尝试{
string name=thread . current thread()。getName();
System.out.println(名称选择衣服);
线程.睡眠(2000年);
同步(这){
System.out.println(名称试穿衣服);
线程.睡眠(2000年);
}
System.out.println(名为退房离开);
} catch (InterruptedException e) {
//TODO自动生成的catch块
e . printstacktrace();
}
}
}运行结果:
线程-1选择衣服
Thread-0选择衣服
试衣
线程1签出并离开
试穿衣服
线程0检验和偏离分析:
两个线程不会同时试穿衣服,因为在试穿会话中设置了同步块,使得线程有序运行试穿会话。
4.用Synchronized 1修改静态方法。如果用Synchronized修改静态方法,那么这些方法必须具有同步效果。
2.静态方法的对象是当前类的对象。
3.类的每个实例用来表示jvm加载一个类。当jvm加载一个类时,它将实例化一个类的实例来表示它。每个类在jvm中只有一个类的实例,所以静态方法锁定当前类对应的类的实例。
公共类Syncdemo3 {
公共静态void main(String[] args) {
线程t1=新线程(){
公共无效运行(){
foo . do some();
}
};
线程t2=新线程(){
公共无效运行(){
foo . do some();
}
};
t1 . start();
T2 . start();
}
}
Foo类
公共同步静态void dosome(){
尝试{
string name=thread . current thread()。getName();
System.out.println(名称运行dosome方法);
thread . sleep(3000);
System.out.println(名称操作结束);
} catch(异常e) {
e . printstacktrace();
}
}
}5.互斥锁使用同步锁定多段代码,而锁的对象相同时,这些代码片段之间就是互斥锁,多个线程不能同时执行这些方法。
公共类同步演示4 {
公共静态void main(String[] args){
Eoo Eoo=new Eoo();
线程t1=新线程(){
公共无效运行(){
eoo。测试01();
}
};
线程t2=新线程(){
公共无效运行(){
eoo。测试02();
}
};
t1。start();
T2。start();
}
}
equal opportunity office 机会均等办公室级
公共同步void test01(){
字符串名称=线程。当前线程().getName();
System.out.println(name 正在运行一方法);
尝试{
线程。睡眠(3000);
} catch (InterruptedException e) {
e。printstacktrace();
}
System.out.println(name 1运行完毕);
}
公共同步void test02(){
字符串名称=线程。当前线程().getName();
System.out.println(name 正在运行2方法);
尝试{
线程。睡眠(3000);
} catch (InterruptedException e) {
e。printstacktrace();
}
System.out.println(name 2运行完毕);
}
}运行结果:
线程-0正在运行一方法
螺纹-01运行完毕
线程一正在运行2方法
螺纹-12运行完毕结果分析:
因为两个线程锁的对象相同,因此,当一个线程运行它的方法时,另一个线程不会一起运行运行它的方法,直到,一个线程运行结束后,他才可以进入这个类,来运行他的方法。
6.死锁现象线程都是保持着自己的锁,但是都是等待对方来释放锁,就出现互相"僵持"的情况,导致程序不会继续向后运行。
公共类同步演示5 {
公共静态void main(String[] args) {
Poo p=new Poo();
线程t1=新线程(){
公共无效运行(){
p。方法1();
}
};
线程t2=新线程(){
公共无效运行(){
p。方法二();
}
};
t1。start();
T2。start();
}
}
便便类
对象A=新对象();
Object B=new Object();
公共空的方法1(){
字符串名称=线程。当前线程().getName();
同步(一){
尝试{
System.out.println(name A正在运行。);
线程。睡眠(3000);
System.out.println(name A运行完毕);
方法二();
} catch(异常e) {
e。printstacktrace();
}
}
}
public void method2(){
字符串名称=线程。当前线程().getName();
同步(B) {
尝试{
System.out.println(name B正在运行。);
线程。睡眠(3000);
System.out.println(name B运行完毕);
方法1();
} catch(异常e) {
e。printstacktrace();
}
}
}
}运行结果:
螺纹-0A正在运行。
螺纹1B正在运行。
螺纹-0A运行完毕
螺纹1B运行完毕结果分析:
虽然有输出结果,但是,程序并没有运行结束,两个线程都等待着对方来释放锁,而僵持不下。
等待()和睡眠()的区别1 .等等是目标类中的方法,睡觉是线中的方法
2.最主要的是睡眠方法调用后,并没有释放锁,使得线程仍然可以同步控制,睡觉不会让出出系统资源,睡觉方法可以在任何地方使用,而等待必须在同步方法或者同步块中使用,否则会抛出异常(Java。郎。illegalmonitorstateexception),等待方法不仅让出cpu,还会释放已占有的同步资源;
3.睡觉必须捕获异常,而等等,诺菲和nofifyAll不需要捕获异常。
4.睡觉是让某个线程暂时运行一段时间,其控制范围是由当前线程决定的,主动权在自己手里,而等等是由某个确定的对象来调用,主动权在某个对象手里。
公共类等待演示{
公共静态void main(String[] args) {
线程t1=新线程my 01();
线程T2=新线程my 02();
t1。start();
T2。start();
}
}
类ThreadMy01扩展了线程{
public static StringBuilder str=new StringBuilder();
公共无效运行(){
字符串名称=线程。当前线程().getName();
同步(字符串){
for(int I=0;i i ){
尝试{
海峡。等待(300);//完全释放锁
//线程。睡眠(300);//不释放锁
海峡。追加( a );
System.out.println(名称字符串);
} catch (InterruptedException e) {
e . printstacktrace();
}
}
}
}
}
//唤醒等待状态
类ThreadMy02扩展了Thread{
公共无效运行(){
synchronized (ThreadMy01.str) {
for(int I=0;i i ){
尝试{
线程.睡眠(2000年);
system . out . println( 888 );
} catch(异常e) {
e . printstacktrace();
}
}
//唤醒wait()状态
thread my 01 . str . notify();
}
}
}运行结果:
888
888
螺纹-0a
螺纹-0aa
螺纹-0aa
螺纹-0aaaa
thread-0 aaaaaa结果分析:
运行上述代码时,sleep睡眠2秒,但不执行wait,这意味着sleep不会放弃系统资源。
线程的生命周期:
版权归作者所有:原创作品来自博主小二上九8,转载请联系作者取得转载授权,否则将追究法律责任。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。