9 Java基础 多线程
来源:互联网 发布:银欣乌鸦2e 数据 编辑:程序博客网 时间:2024/05/17 03:04
/*
进程:是一个正在执行的程序
每一个进程执行都有一个执行顺序 该顺序是一个执行路径 或者叫一个控制单元
线程:就是进程中的一个独立的控制单元
线程在控制着进程的执行
一个进程中至少有一个线程
Java VM 启动的时候会有一个进程Java.exe
该进程中至少有一个线程负责Java程序的执行
而且这个线程运行的代码存在于main方法中
该线程称之为主线程
扩展:其实更细节说明jvm ,jvm启动不止一个线程还有负责垃圾回收机制的线程
1 如何在自定义的代码中,自定义一个线程呢?
通过API的查找 Java已经提供了对线程这类事物的描述就Thread类
创建线程的第一种方法:就是继承Thread类
步骤:
1 定义类 继承thread
2 复写thread类中run方法
目的:将自定义代码存储在run方法 让线程运行
3 调用线程的start方法
该方法有两个作用 :启动线程 调用run方法
发现运行结果每次都不同
因为多个线程都获取cup的执行权 cup执行到谁谁就运行
明确一点在某一个时刻 只能有一个程序在运行(多核除外)
cup 在做着快速的切换 以达到看上去是同时运行的效果
我们可以形象把多线程的运行形容为在互相抢夺cup执行权
这就是多线程的特性:随机性。谁抢到谁执行 至于执行多长时间 cup说的算
为什么要覆盖run方法?
Thread类用于描述线程。
该类定义了一个功能 用于存储线程要运行的代码 。该存储功能就是run方法。
也就是说 Thread类中的run方法,用于存储线程要运行的代码
*/
class demo extends Thread
{
publicvoid run()
{
for(int x=0;x<60 ;x++ )
System.out.println("demorun------"+x);
}
}
class Threaddemo
{
publicstatic void main(String[] args)
{
// for(int x=0;x<400 ;x++ )
// System.out.print("HelloWorld!");
demod =new demo();//创建好一个线程
/*面试*/ d.start();//开启线程并执行该线程的run方法
//d.run();//仅仅是对象的调用方法 而线程创建了 并没有运行
for(int x=0;x<60 ;x++ )
System.out.println("Helloword-----"+x);
}
}
/*
class Threaddemo//run()中什么都没有所以要建立子类继承Thread类覆盖父类方法
{
publicstatic void main(String[] args)
{
Threadt =new Thread();
t.start();//运行没有结果
}
}
*/
/*
练习:
创建两个线程,和主线程交替运行
原来线程都有自己默认的名称
Thread-编号 该编号从0开始。
getName() :获取线程名称
static Thread currentThread():获取当前进程对象
设置线程名称:setName或者构造函数
*/
class Test extends Thread
{
//privateString name;
Test(Stringname)
{
super(name);
//this.name=name;
}
publicvoid run()
{
for(int x=0;x<60 ;x++ )//局部变量在每一个独立的线程区域都有一份
{
System.out.println(Thread.currentThread().getName()+"HelloWorld!----"+x);//返回对象名称Thread.currentThread()
//System.out.println(this.getName()+"HelloWorld!----"+x);
}
}
}
class Threadtest
{
publicstatic void main(String[] args)
{
Testt1=new Test("one---");
Testt2=new Test("two+++");
t1.start();
t2.start();
// t1.run();
// t2.run();
for(int x=0;x<60 ;x++ )
{
System.out.println("main----"+x);
}
}
}
/*
如果同步函数被静态修饰使用的锁是什么?
通过验证发现不再是this 因为静态方法中不可以定义this
静态进内存时内存中没有本类对象但是一定有该类对应的字节码文件对象
类名class 该对象的类型是Class
静态的同步方法使用的锁是该方法锁在类的字节码文件对象类名.class
*/
class Ticket implements Runnable
{
privatestatic int tick =100;//共享数据
//Objectobj =new Object();
booleanflag=true;
public void run()
{
if(flag)
{
while(true)
{
synchronized(Ticket.class)//同一个锁 this
{
if(tick>0)//操作共享数据语句
{
try {Thread.sleep(10);}
catch(Exception e){}
System.out.println(Thread.currentThread().getName()+"code:"+ tick--);
}
}
}
}
else
while(true)
show();
}
public static synchronized void show()//this
{
if(tick>0)//操作共享数据语句
{
try
{
Thread.sleep(10);
}
catch(Exception e)
{
}
System.out.println(Thread.currentThread().getName()+"show-------:"+ tick--);
}
}
}
class Staticmethoddemo
{
publicstatic void main(String[] args)
{
Tickett=new Ticket();
Threadt1=new Thread(t);//创建一个线程
Threadt2=new Thread(t);
// Thread t3=new Thread(t);
// Thread t4=new Thread(t);
t1.start();//调用的是Thread类的run方法
try {Thread.sleep(10);}
catch(Exception e)
{
}
t.flag=false;
t2.start();
// t3.start();
// t4.start();
System.out.println("HelloWorld!");
}
}
/*
同步函数用的是哪一个锁?
函数需要被对象调用那么函数都有一个所属对象引用就是this
所以同步函数使用的锁就是this
通过该程序进行验证
使用两个线程来卖票
一个在同步代码块中
一个线程在同步函数中
都在执行卖票动作
*/
class Ticket implements Runnable
{
private int tick =100;//共享数据
Objectobj =new Object();
booleanflag=true;
public void run()
{
if(flag)
{
while(true)
{
synchronized(this)//同一个锁 this
{
if(tick>0)//操作共享数据语句
{
try {Thread.sleep(10);}
catch(Exception e){}
System.out.println(Thread.currentThread().getName()+"code:"+ tick--);
}
}
}
}
else
while(true)
show();
}
publicsynchronized void show()//this
{
if(tick>0)//操作共享数据语句
{
try
{
Thread.sleep(10);
}
catch(Exception e)
{
}
System.out.println(Thread.currentThread().getName()+"show-------:"+ tick--);
}
}
}
class Thislockdemo
{
publicstatic void main(String[] args)
{
Tickett=new Ticket();
Threadt1=new Thread(t);//创建一个线程
Threadt2=new Thread(t);
// Thread t3=new Thread(t);
// Thread t4=new Thread(t);
t1.start();//调用的是Thread类的run方法
try
{
Thread.sleep(10);
}
catch(Exception e)
{
}
t.flag=false;
t2.start();
// t3.start();
// t4.start();
System.out.println("HelloWorld!");
}
}
/*
单例设计模式。
*/
//饿汉式
/*
class Single
{
privatestatic final Single s= new Single();
privateSingle(){}
publicstatic Single getInstance()
{
returns;
}
}
*/
//懒汉式
class Single
{
privatestatic Single s=null;
privateSingle(){}
publicstatic Single getInstance()
{
if(s==null)//-->A;-->B 会new n多对象
{
synchronized(Single.class)//锁住 只要A满足 其他满足也进不来 创建不了对象
{
if(s==null)
{
s=newSingle();
}
}
}
returns;
}
}
/*
面试:
懒汉式特点:实例的延迟加载如果多线程访问时 会出现安全隐患
可以加同步来解决
加同步的方式:同步代码块和、、、 但有些低效双重判断可以解决效率问题
加同步的时候使用的锁是哪一个?
该类所属的字节码文件对象
*/
class Singledemo
{
publicstatic void main(String[] args)
{
System.out.println("HelloWorld!");
}
}
/*
需求
银行有一个金库
有两个储户分别存300 每次存100 存3次
目的:改程序是否有安全问题如果有如何解决
如何找到问题
1 明确哪些代码是多线程运行代码
2 明确共享数据
3 明确多线程运行代码中哪些语句是操作共享数据的
*/
class Bank
{
privateint sum;//共享数据sum
//Objectobj =new Object();
publicsynchronized void add(int n ) //多线程运行代码方法内的语句
{
//synchronized(obj)//同步
//{
sum=sum+n; //操作共享数据的语句
try
{
Thread.sleep(10);
}
catch(Exception e)
{
}
System.out.println("sum="+sum);//操作共享数据的语句
// }
}
}
class Cus implements Runnable
{
privateBank b=new Bank();//共享数据b
publicvoid run() //多线程运行代码 方法内的语句
{
for(int x=0;x<3 ;x++ )
{
b.add(100);//操作共享数据的语句
}
}
}
class Bankdemo
{
publicstatic void main(String[] args)
{
Cusc=new Cus();
Threadt1=new Thread(c);
Threadt2=new Thread(c);
t1.start();
t2.start();;
// System.out.println("HelloWorld!");
}
}
/*
面试:写死锁要求掌握
*/
class Test implements Runnable
{
privateboolean flag;
Test(booleanflag)
{
this.flag=flag;
}
publicvoid run()
{
if(flag)
{
while(true)
{
synchronized(Mylock.locka)
{
System.out.println("if locka");
synchronized(Mylock.lockb)
{
System.out.println("if lockb");
}
}
}
}
else
{
while(true)
{
synchronized(Mylock.lockb)
{
System.out.println("elselockb");
synchronized(Mylock.locka)
{
System.out.println("elselocka");
}
}
}
}
}
}
class Mylock
{
staticObject locka=new Object();
staticObject lockb=new Object();
}
class Deaddemo
{
publicstatic void main(String[] args)
{
Threadt1=new Thread(new Test(true));
Threadt2=new Thread(new Test(false));
t1.start();
t2.start();
}
}
/*
需求:简单的卖票程序
多个窗口同时卖票
创建线程的第二种方式:实现Runnable接口
步骤;
1 定义类实现Runnable接口
2 覆盖runnable接口中的run方法
将线程要运行的代码存放在该run方法中
3 通过Thread类建立线程对象
4 将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数
为什么要将Runnable接口的子类对象传递给Thread的构造函数
因为 自定义run方法所属的对象是Runnable接口的子类对象
所以要让线程去执行指定对象的run方法 就必须明确该run方法所属的对象
5 调用Thread类的start方法开启线程并调用Runnable接口子类的run方法
面试:实现方式和继承方式有什么区别?
实现方式好处:避免了单继承的局限性
在定义线程时,建议使用实现方式
两种方式区别:
继承Thread:线程代码存放在Thread子类的run方法中
实现Runnable,线程代码存放在接口的子类的run方法中
*/
class Ticket implements Runnable// extendsThread
{
private int tick =100;
publicvoid run()
{
while(true)
{
if(tick>0)
{
System.out.println(Thread.currentThread().getName()+"sale:"+ tick--);
}
}
}
}
class Ticketdemo
{
publicstatic void main(String[] args)
{
Tickett=new Ticket();
Threadt1=new Thread(t);//创建一个线程
Threadt2=new Thread(t);
Threadt3=new Thread(t);
Threadt4=new Thread(t);
t1.start();//调用的是Thread类的run方法
t2.start();
t3.start();
t4.start();
/*
Tickett1=new Ticket();
Tickett2=new Ticket();
Tickett3=new Ticket();
Tickett4=new Ticket();
t1.start();
t2.start();
t3.start();
t4.start();
*/
System.out.println("HelloWorld!");
}
}
/*
通过分析发现打印出0 -1 -2 等错票
多线程运行出现了安全问题
问题的原因:
当多条语句在操作同一个线程共享数据时 一个线程对多条语句只执行了一部分 还没有执行完
另一个线程参与进来执行 导致共享数据的错误
解决办法:
对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中其他线程不可以参与执行
Java对于多线程的安全问题提供了专业的解决方式
就是同步代码块
synchronized(对象)
{
需要被同步的代码
}
对象如同锁。 持有锁的线程可以在同步中执行
没有持有锁的线程即使获取cup的执行权 也进不去 因为没有获取锁
火车上的卫生间---经典
同步的前提:
1必须要有两个或者两个以上的线程
2必须是多个线程使用同一个锁
3必须保证同步中只能有一个线程在运行
好处:解决多线程的安全问题
弊端:多个线程都需要判断锁,较为消耗资源
*/
class Ticket implements Runnable
{
private int tick =1000;//共享数据
Objectobj =new Object();
publicvoid run()
{
while(true)
{
synchronized(obj)//同步
{
if(tick>0)//操作共享数据语句
{
/*
try
{
Thread.sleep(10);
}
catch(Exception e)
{
}
*/
System.out.println(Thread.currentThread().getName()+"sale:"+ tick--);
}
}
}
}
}
class Ticketdemo2
{
publicstatic void main(String[] args)
{
Tickett=new Ticket();
Threadt1=new Thread(t);//创建一个线程
Threadt2=new Thread(t);
Threadt3=new Thread(t);
Threadt4=new Thread(t);
t1.start();//调用的是Thread类的run方法
t2.start();
t3.start();
t4.start();
System.out.println("HelloWorld!");
}
}
- 9 Java基础 多线程
- Java基础/Java多线程
- Java基础-多线程基础篇
- java多线程基础
- Java多线程编程基础
- java多线程开发基础
- Java多线程基础
- Java -- 多线程技术基础
- 【java】多线程基础
- Java基础:多线程
- Java语言基础:多线程
- Java语言基础:多线程
- Java语言基础:多线程
- java多线程基础分析
- Java多线程编程基础
- java 多线程基础
- Java基础_多线程
- Java多线程基础
- 二级以上(包括)界面隐藏TabBar
- Android 百分比适配,轻松解决适配问题
- docker【2】 docker安装 Install Docker Engine
- Fragment 模仿QQ页面之间的转换
- 关于unity3d纹理贴图的学习总结
- 9 Java基础 多线程
- url里含有中文参数,已get方式提交到接口,中文编码后有乱码问题的一种解决
- css 学习
- MySQL中的binlog相关命令和恢复技巧
- mysqlbinlog使用详解
- EditText不能删除、只能输入问题
- spring data jpa 自定义接口
- Java实现输入
- 用HTML5打造本地桌面应用