这边来谈谈java中,我对对多线程的理解
在了解多线程前,先说说进程。
进程就是正在运行的应用程序。 当你打开任务管理器的时候,你就会发现很多的进程。
而我们要说的线程,就是依赖于进程而存在的,一个进程可以开启多个线程。
Thread类
说到线程,就必须来说说Thread类。
Thread类是说有线程的父类。具体请参见api
线程的创建以及执行(图解如下)
继承Thread类,或者实现rennable接口。
当继承了父类后,需要重写父类的run方法,这个run方法里面就写你要执行的代码,当这个线程启动的时候,就会执行你重写的run方法里面的内容。上边的图run里面写的是一个for循环,输出的是一到一百。
线程启动:start方法即可实现。
代码实现:开启线程,并启动,输出结果
public class MyThread extends Thread{
//1.继承Thread类
//2.重写run方法,重写run方法中的代码之后,当我们启动了这个线程之后,我们的这个线程就会执行run方法中的代码
public class MyThread extends Thread{
//1.继承Thread类
//2.重写run方法,重写run方法中的代码之后,当我们启动了这个线程之后,我们的这个线程就会执行run方法中的代码
@Override
public void run() {
//需求:开启该线程之后,执行一个for循环
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
}
//在测试类中启动,来看输出。
//代码实现
public class Test {
public static void main(String[] args) {
//只要我们创建了一个线程对象,并且启动该线程的实例,我们就相当于开启了一///个线程
MyThread mt = new MyThread();
mt.start();//1.开启了一个线程 2.让开启的这个线程执行他对应的类中的run方//法
//在次创建一个子线程,并开启这个子线程执行他的run方法
MyThread mt2 = new MyThread();
mt2.start();
}
最终输出的是我们在run方法里写的for循环。
接下来我们用第二种方法,实现一个runnable接,并重写run方法
public class MyThread implements Runnable{
@Override
public void run() {
//启动该线程对象之后,需要执行的代码
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
}
}
public class MyThread implements Runnable{
@Override
public void run() {
//启动该线程对象之后,需要执行的代码
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
}
}
public class Test {
public static void main(String[] args) {
//创建Mythread对象
MyThread mt = new MyThread();
Thread t1 = new Thread(mt);
t1.start();
}
}
这就是线程的创建和启动
线程的调度和控制
线程休眠(Thread.sleep(毫秒值))
线程名称(setName(),getName();)
线程的调度及优先级setPriority(10)(注意默认值是5,区间在1-10之间)
什么叫线程优先级:说白了就是设置你抢占cpu执行权抢占到的概率
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
MyThread t3 = new MyThread();
//给三个线程设置姓名
t1.setName("刘备");
t2.setName("张飞");
t3.setName("关羽");
//设置线程的优先级
//线程的调度及优先级setPriority(10)(注意默认值是5,区间在1-10之间)
//t1.setPriority(100);//设置的区间必须在1-10之间
t1.setPriority(10);
//开启线程
t1.start();
t2.start();
t3.start();
//共有100张票,将ticket改为静态之后,被类的所有对象所共享
static int ticket = 100;
@Override
public void run() {
//用一个while true循环模拟三个窗口一直处于打开的状态
while (true) {
//只有当ticket>0的时候,才可以出售票
if (ticket>0) {
System.out.println(getName()+"正在出售第:"+ticket--+"张票");
}
}
}
public static void main(String[] args) {
//创建三个线程模拟三个售票窗口
MyThread mt1 = new MyThread();
MyThread mt2 = new MyThread();
MyThread mt3 = new MyThread();
//给线程设置名称
mt1.setName("窗口一");
mt2.setName("窗口二");
mt3.setName("窗口三");
//启动线程,开启售票
mt1.start();
mt2.start();
mt3.start();
}
以上代码是一个售票案例,是一个多线程的案例。
这里说到cpu的执行权。下图简单说说,执行权和执行。 这是那个案例的输出结果,在之后我们会谈到线程不安全性问题。
这里说几点:执行权的抢占是随机的,谁抢到就执行谁,可以通过sleep来验证(详见java相关\第十五天代码+资料)
在使用runnable实现售票案例的时候,在线程睡一会之后,会出现线程安全性问题。
如何解决多线程安全问题
*线程安全执行效率就低
A:同步代码块(测试不是同一个锁的情况,测试是同一个锁的情况)
synchronized(对象) {
需要被同步的代码。
}
需求:1.测试不是同一把锁的时候线程安全吗? 2.如果是同一把锁线程安全吗?
两个问题:1.对象是什么 ?
答:任意对象 ,相当于是一把锁,只要线程进去就把锁锁上
2.需要同步的代码?
答:被线程执行的代码
锁对象问题
a:同步代码
块(定义一个抽象类,里面专门定义一个锁)
任意对象
b:同步方法(仅适用于实现runable接口)
public synchronized void sellTicket(){同步代码}
this
静态同步方法
类的字节码对象
public static synchronized void sellTicket() {
需要同步的代码
}
public class MyThread implements Runnable{
//定义100张票
int ticket = 100;
Object obj = new Object();
@Override
public void run() {
while (true) {
//同步代码块
//synchronized (new Object()) {//t1,t2,t3三个线程不共享同一把锁每个线程都有自己的议案锁
synchronized (obj) {//这样3个线程才可以共享同一把锁
if (ticket>0) {
//考虑到实际的生活中,我们需要给每一个线程加入一定的延迟,模拟一下这种效果
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在出售第:"+ticket--+"张票");
}//当被同步的代码执行完毕之后,t1手里拿着的obj这个锁才会被释放,
//t1,t2,t3重新抢占cpu的执行权,谁抢到了继续拿着obj这个锁,执行同步代码块中的内容
}
}
总之,要解决线程安全性问题,就是上边的方法,关于线程,有好多知识点需要巩固,当然有些东西会在下一次的文章中写(多线程二)。
原文:http://12908151.blog.51cto.com/12898151/1927302