多线程:
1.进程与线程的区别:
进程:进程是系统分配资源调用的一个独立单位.
Eg:任务管理器中.正在运行的程序.(应用客户端等)
2.多线程的意义.提高CPU的使用效率
3.多线程中:线程是同时进行的吗:
不是,是切换进行.CPU的时间片在进程之间高效切换.
4.线程:线程是依赖于进程存在.一个线程相当于进程中的某个任务.
多线程的意义:一个进程中开启多个任务,任务互相抢占CPU的执行权
.线程有随机性. 线程的优先级高不一定抢到线程.
多线程:一个程序的执行路径有多条.
单线程:程序的执行路径只有一条.
JVM是多线程程序吗?
是多线程.由于Java虚拟机自带一个垃圾回收器,保证程序不会轻易的造成溢出
至少开启两个子线程:1.main()主线程 2.垃圾回收线程
实现多线程?
先创建一个进程.
创建进程需要调用系统资源进行创建.但是java语言不能直接调用.
Java使用C/C++封装好的东西.
并发和并行:
并发:同一时间点
并行:同一时间段.
多线程实现方式:
1. 自定义一个类:MyThread继承自Thread类
2. 在MyThread类中重写Thread类的run()方法:为什么重写run()
3. 在主线程成,创建该类的实例对象,启动线程.
Eg
1. 自定义一个类:MyThread继承自Thread类
publicclass MyThread extends Thread {
/*
* 重写Thread类中的run()方法
* */
@Override
public void run() {
// System.out.println("helloworld");
//耗时的操作,线程睡眠,线程等待,循环语句
for(int x = 0 ; x <100 ; x ++){
System.out.println(x);
}
}
}
测试类:
public class MyThreadDemo {
public static void main(String[] args) {
//创建实例对象
// MyThread mt = new MyThread();
//启动线程使用的start()方法.其实JVm调用run方法.start调用
MyThread mt1 = new MyThread() ;
MyThread mt2 = new MyThread() ;
mt1.start();
mt2.start();
}
}
获取线程名称:
Public final String getName()返回线程名称
设置线程名称:
Public final voidsetName(String name)改变线程名称:
public class MyThread extends Thread{
public MyThread(){
}
public MyThread(String name){
super(name) ;
}
@Override
public void run(){
for(int x=100;x<100;x++){
System.out.println(getName()+" "+x);
}
}
}
测试类:
public class ThreadDemo1 {
public static void main(String[] args) {
MyThread my1 = new MyThread() ;
MyThread my2 = new MyThread() ;
// public final void setName(String name)改变线程名称,使之与参数 name 相同。
my1.setName("蛮王") ;
my2.setName("艾希") ;
//main是主线程
// System.out.println(Thread.currentThread().getName());
my1.start() ;
my2.start() ;
}
}
Join方法:
public class JoinThread extends Thread{
@Override
public void run(){
for(int x=0;x<100;x++){
System.out.println(getName()+":"+x);
}
}
}
public class JoinDemo {
public static void main(String[] args) {
JoinThread s1 = new JoinThread();
JoinThread s2 = new JoinThread();
JoinThread s3=new JoinThread();
s1.setName("UZI");
s2.setName("Faker");
s3.setName("Margin");
s1.start();
try {
s1.join() ;
} catch (InterruptedException e) {
e.printStackTrace();
}
s2.start();
s3.start();
}
}
先打印s1的再执行线程s2.s3.
设置线程优先级:
(1-10):默认为5 线程优先级越高也不是一定能抢到CPU线程有随机性.
线程.setPriority(优先级);
Yield():暂停当前执行的线程对象,执行其他的线程.
暂停当前线程执行其他线程,不一定能保证另一个线程就一定抢占到CPU执行权
Public final void setDaemon(boolean on) on指定为true,就是守护线程.
将线程设置为守护线程
该方法必须在启动线程前调用。,对于主线程的数据如果直接输出完毕,对于两个守护线程来说不会立即消失.(慢慢死亡)
public class ThreadDemaonDemo {
public static void main(String[] args) {
ThreadDemaon td1 = new ThreadDemaon();
ThreadDemaontd2 = new ThreadDemaon();
td1.setName("JS") ;
td2.setName("JJ") ;
td1.setDaemon(true);
td2.setDaemon(true);
td1.start();
td2.start();
//设置主线程
Thread.currentThread().setName("剑");
for(int x = 0 ; x <5 ;x++){
System.out.println(Thread.currentThread().getName()+":"+x);
}
}
}
线程睡眠:
public static void sleep(long millis):
throws InterruptedException在指定的毫秒数内让当前正在执行的线程休眠
public class ThreadSleep extends Thread{
@Override
public void run(){
for(int x = 0 ; x <100 ; x ++){
System.out.println(getName()+":"+x+",日期:"+new Date());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}
}
}
}
Public final void stop():强迫线程停止执行.
Public void interrupt():中断线程.一种状态
Runnable接口实现多线程
public class MyRunnable implements Runnable {
@Override
public void run(){
for(int x=0;x<100;x++){
System.out.println(Thread.currentThread().getName()+":"+x);
}
}
}
public class ThreadDemo3 {
public static void main(String[] args) {
MyRunnable MR=new MyRunnable();
// Thread t1 = new Thread();
// t1.setName("线程1");//一种方法
Thread s1 = new Thread(MR,"UZI");
Thread s2 = new Thread(MR,"Faker");
//第二种方法 经常采用
s1.start();
s2.start();
}
}
多线程两种实现方式比较:
一:
1. 自定义一类MyThread继承自Thread类
2. 重写Thread类中的run()方法
3. 主线程创建线程实例
4. 启动线程
注意:启动线程使用start(),调用run()方法相当于调用普通方法.start()的调用实质是通过JVM调用底层run()方法
一个线程不能启动多次,否则出现非法线程状态异常
二:
1. 定义一个MyRunnable,,实习Runnable接口
2. 实现run方法
3. 主线程创建Myrunnble对象
4. 创建Thread类对象,将MyRunnable对象作为参数传递
5. 启动线程
单继承具有局限性:第二种方式更更符合设计原则:数据分类原则.
MyRunnable对象作为子线程的共有对象,java中多线程实习方式接口,方式大于继承
模拟电影院卖票场景,每一个窗口卖票应该延迟操作
在run()方法中加入让线程睡眠
当加入延时操作:可能出现1,0,-1 由于延迟操作和线程的随机性导致的.
解决多线程的安全问题(判断一个多线程是否有安全问题)
1. 是否处在一个多线程环境
2. 是否共享数据
3. 是否多条语句对共享数据进行操作
public class SellTicket implements Runnable {
private static int ticket=100;
@Override
public void run() {
while(true){
if(ticket>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在出售"+(ticket--)+"张票");
}
}
}
}
public class SellTicketDemo {
public static void main(String[] args) {
SellTicket ST= new SellTicket();
Thread s1=new Thread(ST,"窗口1");
Thread s2=new Thread(ST,"窗口2");
Thread s3=new Thread(ST,"窗口3");
s1.start();
s2.start();
s3.start();
}
}
在结果中出现了出售第0票.票的顺序不对.
第二种:
@Override
public void run() {
while (true) {
try {
Thread.sleep(100);
}catch (InterruptedException e) {
e.printStackTrace();
}
if (ticket > 0) {
System.out.println(Thread.currentThread().getName()+ "正在出售第"
+(ticket--) + "张票");
}
}
结果:出现了0票和票的顺序乱的还有重票
解决问题:
1. 多线程环境和共享数据改变不了,同步机制可以改进
条件:将多条语句对共享数据的操作进行更改
2. 将多条语句对共享数据进行操作的代码用代码块包起来
3. Java的同步机制
4. 使用同步代码块:synchronized(同步锁对象){
多条语句对共享数据的操作;
}
public class SellTicketT implements Runnable{
private Demo b=new Demo();
private static int ticket=100;
@Override
public void run() {
while(true){
synchronized(b){
if(ticket>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":"+(ticket--));
}
}
}
}
}
class Demo{
}
锁的对象 b是在开始通过 类Demo 创建.
Synchronize 加锁,以此保证线程安全.
本身锁的对象是Object类型:任意的Java类
可以当做一个门:加锁的时候将门关上,当代码执行完成,门打开,其他人可以进
线程安全的类?
Vector StringBuffer Hashtable
Vector<String> v = new Vector<String>() ;
StringBuffer sb = newStringBuffer("StringHello") ;
Hashtable<String, String> hm = newHashtable<String,String>() ;//Map的子实现类
还有安全的集合列表.
同步锁对象:
1. 可以是Object类型以及任意的Java类型
2. 一个方法进来后是同步代码块,同步代码块可以演变成一个同步方法.
3. 一个静态的同步方法.所对象为当前类名的class 属性.
面试题:
wait()线程等待,notify(),唤醒单个线程,notifyAll():唤醒所有线程这三个方法为什么不定义到Thread类中呢是定义在Object类中?
线程中会存在安全问题,解决线程安全问题使用的同步代码块或者同步方法来解决
同步代码块解决安全问题级出现同步锁对象.因此将方法定义到Object类
静态同步方法:同步锁对象为class
非静态的同步方法:同步锁对象为this