黑马程序员技术交流社区
标题:
多线程
[打印本页]
作者:
lizhichao
时间:
2015-9-7 20:56
标题:
多线程
本帖最后由 lizhichao 于 2015-9-7 20:56 编辑
多线程的概述:
在说多线程的时候我们就已经见识到了很多的多线程的引用。比如1我们电脑的任务管理器。里面有多个应用在运行。我们在聊qq的时候同时与多个好友单独聊天。我们在玩游戏的时候听到劲爆的影音看到逼真的画面。等等。
在了解多线程之前我们首先要了解。一个概念真假多线程。有的时候多线程是cpu间快速切换带来的同时运行的效果。而有的就是多核运算。是真正的多线程。
线程根据cpu的运行可分为 并行和并发:
1,并发:就是指两个任务都请求运行但是cpu仅仅执行一个就是两个任务根据cpu来互相的切换。
2:并行:就是两个线程同时进行A线程在运行的时候B线程也在进行(需要多核cpu)
线程的好处:
1。提高了cpu的效率。当cpu在运行一个线程停歇是就会把cpu转让该另一个线程。
2。更加良好的体验。在我们看电影玩游戏的时候声音与画面的同步是必须的。我击中了目标那么电脑的音响就要传来爆炸的声音。
在学习线程之前就要详细的了解线程与进程:
进程:
进程就是一个正在运行的程序 ,每一个进程都有一个执行的顺序这种顺序就是一个执行的路径也叫一个控制单元。
线程:
一个进程包含n个线程。而线程就是进程的一个独立的控制单元。可以说线程就是一个进程里的进程。线程控制着一个进程的寿命。
当一个进程中还有线程在执行时那么这个进程就没有结束。
Java程序运行原理:
java命令启动jvm虚拟机(java.exe),等于启动一个进程 该进程会自动的启动我们的主函数。(主线程)。它就是一个负责运行我们编写的代码的
线程 然后在主线程运行的时候方法会创建对象 创建的对象 会弹栈于是 那些没有了地址引用的对象就变成了垃圾 他们占用了系统的内存。然后
jvm就会启动它的垃圾清理功能(线程)。这就是java程序的运行原理。显然这是一个多线程的进程。像这种一个进程中多个线程运行的 方式就是多线程。
多线程的实现方式:
1. 继承Thread;
public class Test2 {
public static void main(String[] args) {
MyThread my = new MyThread("线程一");
my.start();
}
}
class MyThread extends Thread{
MyThread(String name){
super(name);
}
public void run(){
for (int i = 0; i < 1000; i++) {
System.out.println(" fi"+this.getName());
}
}
}
复制代码
2. 实现Runnable接口
package it.cast.cn;
public class Thread4 {
public static void main(String[] args) {
Mythread my = new Mythread();
Thread t = new Thread(my,"线程二");
t.start();
}
}
class Mythread implements Runnable{
public void run(){
for (int i = 0; i < 100; i++) {
System.out.println(i+" "+Thread.currentThread().getName());
}
}
}
复制代码
继承Thread 与 实现Runnable的区别:
A:Thread源码解析。由于类继承了Thread所以子类就可以调用父类的非私有方法。而子类又重写了父类的run方法。那么当子类调用了来自父类的start方法时start开启线程后就会调用run方法由于子类重写了父类的run方法所以start就会运行子类的run。
好处:简化了代码
坏处:当子类继承了Thread后就无法再继承其它的类。或者是说如果这个类继承了其它类就无法使用这种方法创建线程。
B:Runnable实现源码解析:由于子类继承的Runnable接口复写了run方法。而Thread有一个有参数的构造。里面接受的就是Runnable类型的参数通过查看源码可以知道。那个构造会把传入Runnable子类对象声明到成员。然后Thread的Run方法会先判断这个成员对象是否为空。为空就不记录如果不为空就调用这个对象的run方法。
好处是:弥补了Thread的短板 用这种方式开启线程的类还可以继承其它的父类。
坏处是:需要创建多个对象。而且代码相对比较复杂。不过这个难不倒高手。
线程的其它方法:
Thread
1 getName();获取线程对象的名字
2.setName();通过setName(String)方法可以设置线程对象的名字
3 static currentThread() 获取本线程对象
static sleep(毫秒);休眠(有异常需要try)1000 = 1秒;
4 setDaemon(boolean);设置守护线程。守护线程会随着其它线程的关闭而关闭。
5 join(),当前线程暂停,等待制定的线程执行完毕。当前线程在继续。
5.1 jion(int) ;可以等待制定的毫秒之后继续。
线程的安全。在多线程计算时每一个线程都有n个语句。那么问题就来了如果一个线程的语句还没有执行完毕或者说才执行了一半 其它的线程就加进来了怎
么办??一个执行了一半的方法时不完整的》所以就用到了同步。同步的思想就是在运行线程的语句未运行完毕时cpu不能切换到其它的线程。破坏正在运行线程的完整。
class Printer {
Demo d = new Demo();
public static void print1() {
synchronized(d){ //锁对象可以是任意对象,但是被锁的代码需要保证是同一把锁,不能用匿名对象
System.out.print("黑");
System.out.print("马");
System.out.print("程");
System.out.print("序");
System.out.print("员");
System.out.print("\r\n");
}
}
public static void print2() {
synchronized(d){
System.out.print("传");
System.out.print("智");
System.out.print("播");
System.out.print("客");
System.out.print("\r\n");
}
}
}
复制代码
自己联习买票的程序
public static void main(String[] args) {
TicketsSeller t1 = new TicketsSeller();
TicketsSeller t2 = new TicketsSeller();
TicketsSeller t3 = new TicketsSeller();
TicketsSeller t4 = new TicketsSeller();
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t4.setName("窗口4");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
class TicketsSeller extends Thread {
private static int tickets = 100;
static Object obj = new Object();
public TicketsSeller() {
super();
}
public TicketsSeller(String name) {
super(name);
}
public void run() {
while(true) {
synchronized(obj) {
if(tickets <= 0)
break;
try {
Thread.sleep(10);//线程1睡,线程2睡,线程3睡,线程4睡
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getName() + "...这是第" + tickets-- + "号票");
}
}
}
}
复制代码
什么叫死锁:
就是线程互相之间不让钥匙。这种现象主要就是出现在锁的嵌套中。
private static String s1 = "筷子左";
private static String s2 = "筷子右";
public static void main(String[] args) {
new Thread() {
public void run() {
while(true) {
synchronized(s1) {
System.out.println(getName() + "...拿到" + s1 + "等待" + s2);
synchronized(s2) {
System.out.println(getName() + "...拿到" + s2 + "开吃");
}
}
}
}
}.start();
new Thread() {
public void run() {
while(true) {
synchronized(s2) {
System.out.println(getName() + "...拿到" + s2 + "等待" + s1);
synchronized(s1) {
System.out.println(getName() + "...拿到" + s1 + "开吃");
}
}
}
}
}.start();
}
复制代码
作者:
lizhichao
时间:
2015-9-7 21:20
内容缺了
线程的几种状态
1 被创建 start()开始
2 待运行 ;cpu分配执行权和执行资格
3 临时阻塞 :有执行资格没有执行权
4 冻结 线程突然失去 执行权和执行资格、代表方法 sleep wait 注意sleep会释放锁对象
5 消亡 线程运算完毕。或者是调用了一个已经过时的方法stop。
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/)
黑马程序员IT技术论坛 X3.2