java基础学习多线程学习笔记
来源:互联网 发布:从程序员到软件工程师 编辑:程序博客网 时间:2024/05/05 22:47
------- android培训、java培训、期待与您交流! ----------
1:多线程
(1)多线程
进程:正在运行的程序叫进程
线程:进程在执行过程中,可能需要多个任务同时执行,每个任务的执行者就是线程
(2)jvm启动是多线程
(3)如何实现多线程:
A:继承Thread类
步骤:
**定义一个类,继承Thread类
**重写run方法
**调用start方法.
**启动线程
**调用run方法
Thread类中的常用方法:
**Thread(String name):通过构造给线程起名字
**setName(String name):通过set方法给线程起名字
**getName():获取线程的名称
**currentThread():获取当前线程的一个对象引用
***获取哪些没有直接继续Thread类的线程名称
B:实现Runnable接口
步骤:
**定义一个类,实现Runnable接口
**重写run方法
**创建实现了Runnable接口的子类对象,并把该对象作为参数传递给
Thread类的对象.这个时候,调用Thread类的start方法.
(4)线程的生命周期
A:创建
B:就绪
C:运行
D:阻塞 sleep,wait导致阻塞
sleep的时间到了,wait的被唤醒了.就到了就绪状态
E:死亡
(5)卖票的问题
A:继承Thread实现卖票
这个时候,我们的票需要定义为静态的.但是呢,我们不建议这样做.
B:实现Runnable接口卖票
在这里,发现卖票出了问题.(线程安全问题)
线程安全问题的产生:
**多个线程延迟访问
**线程的随机性
(6)解决线程安全问题
A:同步代码块
格式: synchronized(对象)
{
//被同步的代码,也就是可能出现安全问题的代码
}
示例:
给卖票程序示例加上同步代码块。
class Ticket implements Runnable
{
private int tick=100;
Object obj = new Object();
public void run()
{
while(true)
{
//给程序加同步,即锁
synchronized(obj)
{
if(tick>0)
{
try
{
//使用线程中的sleep方法,模拟线程出现的安全问题
//因为sleep方法有异常声明,所以这里要对其进行处理
Thread.sleep(10);
}
catch (Exception e)
{
}
//显示线程名及余票数
System.out.println(Thread.currentThread().getName()+"..tick="+tick--);
}
}
}
}
}
B:同步方法
就是在方法上加synchronized关键字即可.
C:同步的前提:
**同步需要两个或者两个以上的线程
**多个线程使用的是同一个锁。
未满足这两个条件,不能称其为同步。
示例:
class Ticket implements Runnable
{
private int tick=100;
Object obj = new Object();
public void run()
{
while(true)
{
show();
}
}
//直接在函数上用synchronized修饰即可实现同步
public synchronized void show()
{
if(tick>0)
{
try
{
//使用线程中的sleep方法,模拟线程出现的安全问题
//因为sleep方法有异常声明,所以这里要对其进行处理
Thread.sleep(10);
}
catch (Exception e)
{
}
//显示线程名及余票数
System.out.println(Thread.currentThread().getName()+"..tick="+tick--);
}
}
}
静态函数的同步方式
如果同步函数被静态修饰后,使用的锁是什么呢?
通过验证,发现不在是this。因为静态方法中也不可以定义this。静态进内存时,内存中没有本类对象,但是一定有该类对应的字节码文件对象。如:
类名.class 该对象的类型是Class
这就是静态函数所使用的锁。而静态的同步方法,使用的锁是该方法所在类的字节码文件对象。类名.class
示例:
/*
加同步的单例设计模式————懒汉式
*/
class Single
{
private static Single s = null;
private Single(){}
public static void getInstance()
{
if(s==null)
{
synchronized(Single.class)
{
if(s==null)
s = new Single();
}
}
return s;
}
}
D:同步的弊端:
当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,
无形中会降低程序的运行效率。
同步可能造成死锁问题:
死锁的产生:
你拿着我们的锁,我拿着你的锁,谁都不先对方用.
针对程序来说,就是我想用你的锁,而你也想用我的锁.都不放手.导致了死锁.
死锁
当同步中嵌套同步时,就有可能出现死锁现象。
示例:写一个死锁程序
*/
//定义一个类来实现Runnable,并复写run方法
class LockTest implements Runnable
{
private boolean flag;
LockTest(boolean flag)
{
this.flag=flag;
}
public void run()
{
if(flag)
{
while(true)
{
synchronized(LockClass.locka)//a锁
{
System.out.println(Thread.currentThread().getName()+"------if_locka");
synchronized(LockClass.lockb)//b锁
{
System.out.println(Thread.currentThread().getName()+"------if_lockb");
}
}
}
}
else
{
while(true)
{
synchronized(LockClass.lockb)//b锁
{
System.out.println(Thread.currentThread().getName()+"------else_lockb");
synchronized(LockClass.locka)//a锁
{
System.out.println(Thread.currentThread().getName()+"------else_locka");
}
}
}
}
}
}
//定义两个锁
class LockClass
{
static Object locka = new Object();
static Object lockb = new Object();
}
class DeadLock
{
public static void main(String[] args)
{
//创建2个进程,并启动
new Thread(new LockTest(true)).start();
new Thread(new LockTest(false)).start();
}
}
3:线程间的通信
(1)以前操作一个资源的时候,用的是同一种类型的线程来进行多线程的操作.
现在,我们对一个资源的操作,用不同种类型的线程来操作,这不同类型间的线程是有关系的.
这就称作线程间的通信.
举例:
我们既可以从自己的卡里取钱,也可以往卡里存钱.
(2)资源:可能是一个基本数据类型,也可能是一个引用类型.还可能是一个大的容器.
(3)我们有一个学生资源,我们可以输出学生,也可以设置学生信息.
并且,你可以多次输出学生信息,也可以多次设置学生信息.
用此例模拟线程间的通信.
重点.
public class Student
{
String name;
int age;
}
//设置值
public class Input implements Runnable
{
private Student s;
public Input(Student s)
{
this.s = s;
}
public void run()
{
//设置值
int x = 0;
while(true)
{
synchronized(s)
{
if(x%2==0)
{
s.name = "张三";
s.age = 40;
}
else
{
s.name = "李四";
s.age = 30;
}
}
x++;
}
}
}
//获取值
public class Output implements Runnable
{
private Student s;
public Output(Student s)
{
this.s = s;
}
public void run()
{
//获取值
while(true)
{
synchronized(s)
{
System.out.println(s.name+"***"+s.age);
}
}
}
}
//测试类
public class StudentTest
{
public static void main(String[] args)
{
Studnet s = new Student();
Input in = new Input(s);
Output out = new Output(s);
Thread t1 = new Thread(in);
Thread t2 = new Thread(out);
t1.start();
t2.start();
}
}
(4)解决数据一个的互相输出问题
wait:让线程等待
notify:唤醒线程池中的第一个线程
notifyAll:唤醒线程池中的所有线程
(5)为什么这些方法定义在了Object类中.
1,这些方法存在与同步中。
2,使用这些方法时必须要标识所属的同步的锁。
3,锁可以是任意对象,所以任意对象调用的方法一定定义Object类中。
2.JDK1.5中提供了多线程升级解决方案。
将同步synchronized替换成显示的Lock操作。将Object中wait,notify,notifyAll,替换成了Condition对象。该Condition对象可以通过Lock锁进行获取,并支持多个相关的Condition对象。
升级解决方案的示例:
/*生产者生产商品,供消费者使用
有两个或者多个生产者,生产一次就等待消费一次
有两个或者多个消费者,等待生产者生产一次就消费掉
*/
import java.util.concurrent.locks.*;
class Resource
{
private String name;
private int count=1;
private boolean flag = false;
//多态
private Lock lock=new ReentrantLock();
//创建两Condition对象,分别来控制等待或唤醒本方和对方线程
Condition condition_pro=lock.newCondition();
Condition condition_con=lock.newCondition();
//p1、p2共享此方法
public void setProducer(String name)throws InterruptedException
{
lock.lock();//锁
try
{
while(flag)//重复判断标识,确认是否生产
condition_pro.await();//本方等待
this.name=name+"......"+count++;//生产
System.out.println(Thread.currentThread().getName()+"...生产..."+this.name);//打印生产
flag=true;//控制生产\消费标识
condition_con.signal();//唤醒对方
}
finally
{
lock.unlock();//解锁,这个动作一定执行
}
}
//c1、c2共享此方法
public void getConsumer()throws InterruptedException
{
lock.lock();
try
{
while(!flag)//重复判断标识,确认是否可以消费
condition_con.await();
System.out.println(Thread.currentThread().getName()+".消费."+this.name);//打印消费
flag=false;//控制生产\消费标识
condition_pro.signal();
}
finally
{
lock.unlock();
}
}
}
//生产者线程
class Producer implements Runnable
{
private Resource res;
Producer(Resource res)
{
this.res=res;
}
//复写run方法
public void run()
{
while(true)
{
try
{
res.setProducer("商品");
}
catch (InterruptedException e)
{
}
}
}
}
//消费者线程
class Consumer implements Runnable
{
private Resource res;
Consumer(Resource res)
{
this.res=res;
}
//复写run
public void run()
{
while(true)
{
try
{
res.getConsumer();
}
catch (InterruptedException e)
{
}
}
}
}
class ProducerConsumer
{
public static void main(String[] args)
{
Resource res=new Resource();
new Thread(new Producer(res)).start();//第一个生产线程 p1
new Thread(new Consumer(res)).start();//第一个消费线程 c1
new Thread(new Producer(res)).start();//第二个生产线程 p2
new Thread(new Consumer(res)).start();//第二个消费线程 c2
}
}
(6)wait(),sleep()的区别:
A:wait()可有无参数的调用.
而sleep必须指定睡眠时间.但是有些时候,睡眠时间不好确定.这个时候就可以使用wait.
B:wait:释放了执行权,释放锁.
sleep:释放了执行权,不释放锁.
sleep有醒过来的时候,而wait可能醒不了.
(7)停止线程的方式:
A:通过stop方法停止线程.但是这个方法过时,所以不推荐使用.使用 interrupt方法来中断该等待
B:线程中的代码一般都是在循环中的.可以通过控制循环的次数来让run方法结束.
(8)常见的几个方法:
A:interrupt方法的使用. 强制中断线程
B:setDaemon(boolean on):守护线程
C:join 加入线程.拥有最高的执行权.其他的线程都得给它让路.
D:优先级 范围(1-10); 默认是5.
E:给线程设置名称 setName();
什么时候写多线程?
当某些代码需要同时被执行时,就用单独的线程进行封装。
示例:
class ThreadTest{
public static void main(String[] args)
{
//一条线程
new Thread()
{
public void run()
{
for (int x=0;x<100 ;x++ )
{
System.out.println(Thread.currentThread().toString()+"....."+x);
}
}
}.start();
//又是一条线程
Runnable r= new Runnable()
{
public void run()
{
for (int x=0;x<100 ;x++ )
{
System.out.println(Thread.currentThread().getName()+"....."+x);
}
}
};
new Thread(r).start();
//可以看作主线程
for (int x=0;x<1000 ;x++ )
{
System.out.println("Hello World!");
}
}
}
- java基础学习多线程学习笔记
- java基础学习笔记_多线程
- 学习笔记--java基础--多线程基本概念
- java基础学习--多线程
- Java多线程基础学习
- Java多线程基础学习
- Java多线程学习笔记
- Java多线程学习笔记
- Java学习笔记---多线程
- java多线程学习笔记
- Java多线程学习笔记
- Java多线程学习笔记
- JAVA多线程学习笔记
- Java 多线程学习笔记
- java多线程学习笔记
- Java多线程学习笔记
- [学习笔记]Java多线程
- java多线程学习笔记
- ios开发数组排序(数组中包括字典)
- Windows线程池
- iOS 带cookie进行网络请求
- WPARAM和LPARAM一看就得知道是消息的附加参数
- 海量数据处理:十道面试题与十个海量数据处理方法总结
- java基础学习多线程学习笔记
- 微信公众平台开发(2)回复超链接
- QT串口工具(3)
- 堆和栈的区别
- “珠西”经济带,南海新机遇
- hibernate 基本步骤
- POJ2833The Average【堆排序】
- 裴蜀定理
- hdu5396(2015多校9)--Expression(区间dp)