多线程
- 进程
- 线程 (例:FlashGet
- 多线程存在的意义
- 线程的创建方式
- 多线程的特性
创建线程的第一种方式:继承Thread类
步骤:
- 定义类继承Thread
- 复写Thread类中的run方法
- 目的:将自定义的代码存储在run方法中,让线程运行
- 调用线程的start方法
- 该方法两个作用:启动线程,调用run方法
package 多线程.继承Thread;
class Demo extends Thread//继承Thread
{
public void run()//复写run方法
{
for(int x=0;x<100;x++)
{
System.out.println("Demo run--"+x);
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
Demo d=new Demo();//创建对象
d.start();//启动线程
for(int x=0;x<100;x++)
{
System.out.println("Main--"+x);
}
}
}
线程都有默认名称
Thread-编号 该编号从0开始
通过this.getName()获取当前线程名称
通过 线程对象.setName(String name)可以设置线程名称
通过构造函数设置线程名称
class Demo extends Thread
{
public Demo()//默认构造函数
{
super();
}
public Demo(String name)//通过name参数构造带名称的线程
{
super(name);
}
public void run()
{
for(int x=0;x<100;x++)
{
System.out.println(this.getName()+"--"+x);
}
}
}
获取当前线程对象
static Thread.currentThread()
创建线程的第二种方法:实现Runnable接口
- 定义类实现Runnable接口
- 覆盖Runnable接口中的run方法
- 通过Thread类建立线程对象
- 将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数
- 调用Thread类的start方法开启线程并调用Runnable接口子类的run方法。
class RunDemo implements Runnable
{
private int tick=100;
@Override
public void run() {
// TODO Auto-generated method stub
while(true)
{
if(tick>0)
{
System.out.println(Thread.currentThread().getName()+" "+tick--);
}
else
break;
}
}
}
public class RunnableDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
RunDemo rd=new RunDemo();
Thread t1=new Thread(rd);
Thread t2=new Thread(rd);
Thread t3=new Thread(rd);
Thread t4=new Thread(rd);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
实现方式好处:避免了单继承的局限性。
在定义线程时,建立使用实现方式。
两种方式区别:
继承Thread:线程代码存放在Thread子类run方法中。
实现Runnable,线程代码存放在接口的子类的run方法。
多线程安全问题
当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没执行完,另一个线程参与进来执行。导致共享数据的错误。
使用同步代码块。
synchronized(对象)
{
需要被同步的代码
}
同步的前提:
1. 必须要有两个或者两个以上的线程
2. 必须是多个线程使用同一个锁
好处:解决了多线程的安全问题。
弊端:多个线程需要判断锁,较为消耗资源
使用同步函数:
public synchronized void add(int n)
{
//synchronized(obj)
//{
sum=sum+n;
System.out.println("sum="+sum);
//}
}
同步函数的锁是this
class Ticket implements Runnable//创建类,实现接口Runnable,实现run方法
{
private int tick=100;
public boolean flag=true;
@Override
public void run() {
// TODO Auto-generated method stub
if(flag)
{
while(true){
synchronized(this)//使用this对象作为锁
{
if(tick>0)
{
try
{
Thread.sleep(2);
}
catch(Exception e){ }
System.out.println(Thread.currentThread().getName()+" "+tick--);
}
else
break;
}
}
}
else
while(show()){ }
}
public synchronized boolean show()//同步函数的锁是this
{
if(tick>0)
{
try
{
Thread.sleep(2);
}
catch(Exception e){ }
System.out.println(Thread.currentThread().getName()+" "+tick--);
return true;
}
else
return false;
}
}
public class ThisLockDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
Ticket t=new Ticket();//创建run方法的对象
Thread t1=new Thread(t);//创建线程1,传递Runnable接口的实现类的对象
Thread t2=new Thread(t);//创建线程2,传递Runnable接口的实现类的对象
t1.start();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
t.flag=false;//t1执行同步代码块
t2.start();//t2执行同步函数
//t1,t2用同一个锁this,所以不会同时执行,也就不会发生对同一个变量同时操作的危险。
}
}
静态同步函数的锁是 Class对象
静态的同步方法使用的锁是该方法所在类的字节码文件对象
类名.class 该对象的类型是Class
单例设计模式 懒汉式
package 多线程.懒汉式;
class Single
{
private static Single s;//声明静态的Single类对象s,保证只有一个s对象
private int x;
private Single(){}//构造方法私有化,禁止创建多个对象
public static Single getInstance()//只能通过静态方法getInstance获取Single类的实例
{
if(s==null)//第一重判断
{
synchronized(Single.class){//加同步锁,防止多个线程进入
if(s==null)//第二重判断,保证只有一个实例对象
s=new Single();//如果没有创建对象实例,就创建实例
}
}
return s;//返回Single类的对象引用
}
public void show()
{
while(true)
{
synchronized(this)//加入同步,防止多个线程操作共享数据x时发生同时进入代码操作。
{
if(x<100)
{
try
{
Thread.sleep(1);
}
catch(Exception e)
{
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":"+x++);
}
else
break;
}
}
}
}
class MyThread extends Thread//继承Thread类覆盖run方法实现自己的线程功能
{
public void run()
{
Single s=Single.getInstance();//线程获取对象
s.show();//线程使用对象方法
}
}
public class SingleDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
MyThread t1=new MyThread();//创建线程1
MyThread t2=new MyThread();//创建线程2
t1.start();//启动线程1
t2.start();//启动线程2
}
}