一、创建方式
1. 实现runable接口
步骤:1.创建类实现runable接口重写run方法
2.建立类的实例对象
3.将实例对象放在new thread中
4.调用thread类中start方法调用run方法
public class textrunable {
public static void main(String[] args) {
/*
//创建实现类对象
B b=new B();
//创建实现代理对象
Thread ss=new Thread(b);
ss.start();
*/
new Thread(new B()).start();//匿名对象与上述所实现用法相同
for(int i=0;i<20;i++) {
System.out.println("I am a hero");
}
}
}
class B implements Runnable{
@Override
public void run() {
for(int i=0;i<20;i++) {
System.out.println("you are a foolish");
}
}
}
2. 继承Thread类(是runable接口的实现类)
步骤:1.创建类继承thread类重写run方法
2.建立类的实例对象
3.调用start方法运行
public class textthread {
public static void main(String[] args) {
A a=new A();
a.start();
for(int i=0;i<20;i++) {
System.out.println("eat fish");
}
}
}
class A extends Thread{
public void run() {
for(int i=0;i<20;i++) {
System.out.println("study");
}
}
}
3. 实现callable接口
步骤:1.创建类实现callable接口并重写all类(此方法与run不同可以有返回值)
2.建立实例对象
3.放到futuretask()中
4.使用new thread。start启动线程
ublic class CallableTest {
public static void main(String[] args) {
test0 test0=new test0();
FutureTask<Integer> f = new FutureTask<>(test0);
new Thread(f).start();
try {
/*此方法可以得到call方法内的返回值*/
Integer integer = f.get();
System.out.println(integer);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
class test0 implements Callable<Integer>{
@Override
public Integer call() throws Exception {
int sum=0;
for (int i=0;i<10;i++){
sum+=i;
}
return sum;
}
}
4. 使用线程池
方法如下
public class ThreadPool {
public static void main(String[] args) {
/*建立一个线程池*/
ExecutorService service = Executors.newFixedThreadPool(10);
/*创建实例*/
test1 test1 = new test1();
/*执行提交*/
service.execute(test1);
service.submit(new test2());
/*关闭线程池*/
service.shutdown();
}
}
class test1 implements Runnable {
@Override
public void run() {
//int sum=0;
for (int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+i);
}
}
}
class test2 implements Callable<Integer>{
@Override
public Integer call() throws Exception {
int sum=0;
for (int i=0;i<10;i++){
System.out.println(sum+=i);
}
return sum;
}
}
二、线程同步
1. synchronized代码块
如果是代码块的形式 继承thread 那么这个this类 不是一个唯一的对象所以锁不住需要调用 this.class使用它的类锁住 而第二种实现runable接口则只创建了一个对象所以说this是一个唯一对象就可以锁住
synchronized代码块的基本使用,以下便不一一列举了。
public class textCynchronized {
public static void main(String[] args) {
t12306 tt=new t12306();
new Thread(tt,"1号").start();
new Thread(tt,"2号").start();
}
}
class t12306 implements Runnable{
private int tackit=10;
private boolean flag=true;
@Override
public void run() {
while(flag) {
stop();
}
return;
}
public void stop() {
synchronized (this) {
if(tackit<=0) {
flag=false;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("取票人"+Thread.currentThread().getName()+"--->"+tackit--);
}
}
}
2. synchronized方法
使用同步方法也需要主要上面所强调的this对象是否唯一的问题 因为同步方法 使用synchronize关键字默认 使用的锁对象(唯一对象)就是this ,这是使用实现runable接口的方式创建没用问题,但是要是继承thread的方式创建仍然是线程不安全,你需要在方法上加static关键字这就使得上升到了类的层面所以就符合了唯一对象的局限性
3. 建立lock实例
首先在你要保证线程安全的类中建立一个lock类用于实现线程的安全问题,以上所述lock是一个接口需要建立他的实例需要用它的实现类比如ReentrantLock用于建立对象,此时他所获得的锁仍然是this对象,所以必须只有一个实例,使用lock方法获得锁,使用unlock方法解除锁,此方法使锁定的范围设置变得更加灵活。
4. 线程的通信(必须建立在synchronized代码块或synchronized方法中使用)
线程的通信主要使用阻塞方法:wait()(此方法在执行时会释放当前锁,也就是synchronized中的锁),通知解除阻塞的方法:notify(),notifyAll()。
以上三个方法并不是thread中的方法,而是object中的方法。意思就是任何一个对象都可以调用。
通过这样通信阻塞的方法就可以实现线程的交互。
以下是一个线程安全的简单例子
public class test {
public static void main(String[] args) {
Access ass = new Access();
Custorm no1 = new Custorm(ass, 1000, null, true);
Custorm no2 = new Custorm(ass, 1000, null, true);
Thread thread = new Thread(no1);
Thread thread1 = new Thread(no2);
thread.start();
thread1.start();
}
}
class Custorm implements Runnable{
private Access access;
private Integer savecount;
private Integer outcount;
private boolean flag;
public Custorm(Access access, Integer savecount, Integer outcount, boolean flag) {
this.access = access;
this.savecount = savecount;
this.outcount = outcount;
this.flag = flag;
}
public void savemoney(){
synchronized (access){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
access.setMoney(access.getMoney()+savecount);
System.out.println(Thread.currentThread().getName()+"存入"+this.savecount+"余额为:"+access.getMoney());
}
}
public void outmoney() {
if (access.getMoney()>outcount){
System.out.println(Thread.currentThread().getName()+"取出"+this.outcount+"余额为:"+access.getMoney());
access.setMoney(access.getMoney()-outcount);
}else {
System.out.println("余额不足");
}
}
@Override
public void run() {
for (int i = 0; i <= 6; i++) {
if (flag) {
savemoney();
} else {
outmoney();
}
}
}
}
class Access{
private Integer money=3000;
public Access() {
}
public Integer getMoney() {
return money;
}
public void setMoney(Integer money) {
this.money = money;
}
}