//15同步问题的分析案例以及解决思路

 //两个客户到一个银行去存钱,每个客户一次存100,存3次。
//问题,该程序是否有安全问题,如果有,写出分析过程,并定于解决方案。 /*
发现运行结果:
sum=200
sum=200
sum=300
sum=400
sum=600
sum=500 打印错乱,不关心,但是发现数值错误,没有100.
运行了几次,发现有对的。 说明多线程的随机性造成了安全问题。
哪的问题?
1,既然是多线程的问题,必须问题发生在多线程中
2,任务代码中是否有共性数据呢?b对象中的sum.
3,是否有对sum进行多次运算呢?有! 加同步就行了。
*/
//描述银行,
class Bank
{
private int sum;
private Object obj = new Object();
public void add(int num)
{
synchronized(obj)
{
sum = sum+num;
System.out.println("sum="+sum);//每存一次,看到银行金额变化。
}
}
} class Consumer implements Runnable
{
private Bank b = new Bank();
public void run()
{
for(int x=0;x<3;x++)
{
b.add(100);//一次存100,循环3次。
}
}
}
class ThreadTest
{
public static void main(String[] args)
{
Consumer c = new Consumer();
Thread t1 = new Thread(c);
Thread t2 = new Thread(c);
t1.start();
t2.start();
}
}
 //同步函数相关问题,以及同步函数和同步代码块的比较
/*
同步的另一种体现形式。同步函数。 同步函数使用的锁是哪个?
经过简单的分析:大概猜的是this。因为函数必须被对象调用。 验证:
写一个同步代码块,写一个同步函数。如果同步代码块中的锁对象和同步函数中的锁对象
是同一个,就同步了,就没有错误的数据了,如果不是同一个锁对象,就不同步,会出现错误数据, 让两个线程,一个线程在同步代码块中执行,一个线程待同步函数中执行。 总结:同步函数使用的锁是this. 同步函数和同步代码块的的区别?
1,同步函数使用的锁是固定的this。当线程任务只需要一个同步时,完全可以通过同步函数来体现。
2,同步代码块使用的是锁可以是任意对象。当线程任务需要多个同步时,必须通过所来区分。这时必须使用同步代码块。
同步代码块较为常用。 如果只用一个同步时,完全可以简化为
*/ class Ticket implements Runnable
{
//1,描述票的数量
private int tickets = 100; //2,售票的动作。这个动作需要被多线程执行,那就是线程任务代码,
//需要定义在run方法中。
//记住,线程任务中通常都有循环结构。
//private Object obj = new Object();
boolean flag = true;
public void run()
{
if(flag){
while(true)
{
synchronized(this)
{
if(tickets > 0)
{
try{Thread.sleep(1);}catch(InterruptedException e){/*未写处理方式,后面讲*/}
System.out.println(Thread.currentThread().getName()+"..obj.."+tickets--);//打印线程名称
}
}
}
} else{
while(true)
{
this.sale();
}
}
} public synchronized void sale()//同步函数。具备了同步性的函数,使用的锁对象就是this
{
if(tickets > 0)
{
//要让线程在这里稍停,模拟问题的发生。sleep 看到了 0 -1 -2 这样的错误的数据,这就是传说中的安全问题。
try{Thread.sleep(1);}catch(InterruptedException e){/*未写处理方式,后面讲*/}
System.out.println(Thread.currentThread().getName()+"..sale.."+tickets--);//打印线程名称
}
}
} class ThreadDemo4
{
public void main(String[] args)
{
//1,创建Runnable接口的子类对象。
Ticket t = new Ticket(); //创建四个线程对象。并将Runnable接口的子类对象作为参数传递给Thread的构造函数。
Thread t1 = new Thread(t);
Thread t2 = new Thread(t); //3,开启四个线程
t1.start(); try{Thread.sleep(10);}catch(InterruptedException e){}
//切换标记;之前,让主线程停一会儿,这时就只有一个t1线程在。
t.flag = false; t2.start();
}
}
 /*
静态同步函数使用的锁不是this.而是字节码文件对象。类名.class
*/ class Ticket implements Runnable
{
//1,描述票的数量
private static int tickets = 100; //2,售票的动作。这个动作需要被多线程执行,那就是线程任务代码,
//需要定义在run方法中。
//记住,线程任务中通常都有循环结构。
//private Object obj = new Object();
boolean flag = true;
public void run()
{
if(flag){
while(true)
{
synchronized(Ticket.class)
{
if(tickets > 0)
{
try{Thread.sleep(1);}catch(InterruptedException e){/*未写处理方式,后面讲*/}
System.out.println(Thread.currentThread().getName()+"..obj.."+tickets--);//打印线程名称
}
}
}
} else{
while(true)
{
this.sale();
}
}
} public static synchronized void sale()//加了静态后,已经知道静态函数里面没有了this.
{
if(tickets > 0)
{
//要让线程在这里稍停,模拟问题的发生。sleep 看到了 0 -1 -2 这样的错误的数据,这就是传说中的安全问题。
try{Thread.sleep(1);}catch(InterruptedException e){/*未写处理方式,后面讲*/}
System.out.println(Thread.currentThread().getName()+"..sale.."+tickets--);//打印线程名称
}
}
} class ThreadDemo5
{
public static void main(String[] args)
{
//1,创建Runnable接口的子类对象。
Ticket t = new Ticket(); //创建四个线程对象。并将Runnable接口的子类对象作为参数传递给Thread的构造函数。
Thread t1 = new Thread(t);
Thread t2 = new Thread(t); //3,开启四个线程
t1.start(); try{Thread.sleep(10);}catch(InterruptedException e){}
//切换标记;之前,让主线程停一会儿,这时就只有一个t1线程在。
t.flag = false; t2.start();
}
}
 //单例懒汉模式的并发访问相关问题
/*
单例懒汉模式的并发访问相关问题
*/ //饿汉式;多线程并发没问题。
class Single
{
private static final Single s = new Single(); private Single(){} public static Single getInstance()
{
return s;
}
} //懒汉式:
class Single
{
private static Single s = null; private Single(){}
/*
并发访问,会有安全隐患,所以加入同步机制解决安全问题。
但是,同步的出现却降低了效率。(提稿效率的办法就是减少判断锁的次数)
可以通过双重判断的方式,解决效率问题,减少判断的次数。 */
public static /*synchronized*/ Single getInstance()
{
if(s==null)//只要有一个线程把对象创建完,其他线程就再也不会判断锁了。
{
synchronized(Single.class)
{
if(s==null)
// --->0 --->1
s = new Single();
}
}
return s;
}
}
class Demo implements Runnable
{
public void run()
{
Single.getInstance();
}
} class ThreadDemo6
{
public static void main(String[] args)
{
System.out.println("Hello World!");
}
}
 //同步的另一个弊端。死锁
/*
同步的另一个弊端。 情况之一:当线程任务中出现了多个同步(多个锁)时,如果同步中嵌套了其他的同步。
这时容易引发一种现象,死锁。
这种情况能避免就避免。 //Thread-0
synchronized(obj1)
{
--->thread-0 obj1
synchronized(obj2)
{ }
} //Thread-1
synchronized(obj2)
{
thread-1 obj2
synchronized(obj1)
{ }
} */ class Ticket implements Runnable
{
//1,描述票的数量
private int tickets = 100; //2,售票的动作。这个动作需要被多线程执行,那就是线程任务代码,
//需要定义在run方法中。
//记住,线程任务中通常都有循环结构。
private Object obj = new Object();
boolean flag = true;
public void run()
{
if(flag){
while(true)
{
synchronized(obj)//obj锁
{
sale();//this锁
}
}
} else{
while(true)
{
this.sale();
}
}
} public synchronized void sale()//this锁
{
synchronized(obj)//obj锁
{
if(tickets > 0)
{
//要让线程在这里稍停,模拟问题的发生。sleep 看到了 0 -1 -2 这样的错误的数据,这就是传说中的安全问题。
try{Thread.sleep(1);}catch(InterruptedException e){/*未写处理方式,后面讲*/}
System.out.println(Thread.currentThread().getName()+"..sale.."+tickets--);//打印线程名称
}
}
}
} class ThreadDemo7
{
public static void main(String[] args)
{
//1,创建Runnable接口的子类对象。
Ticket t = new Ticket(); //创建四个线程对象。并将Runnable接口的子类对象作为参数传递给Thread的构造函数。
Thread t1 = new Thread(t);
Thread t2 = new Thread(t); //3,开启四个线程
t1.start(); try{Thread.sleep(10);}catch(InterruptedException e){}
//切换标记;之前,让主线程停一会儿,这时就只有一个t1线程在。
t.flag = false; t2.start();
}
} //这个程序在运行过程中死锁了。
/*
Thread-0..sale..100
Thread-0..sale..99
Thread-0..sale..98
Thread-0..sale..97
Thread-0..sale..96
Thread-0..sale..95
*/
 //死锁示例--面试会用到
class Test implements Runnable
{
private boolean flag;
Test(boolean flag)
{
this.flag = flag;
}
public void run()
{
if(flag)
{
while(true)
{
synchronized(MyLock.LOCKA)
{
System.out.println(Thread.currentThread().getName()+"if......locka");
synchronized(MyLock.LOCKB)
{
System.out.println(Thread.currentThread().getName()+"if......lockb");
}
}
}
}
else
{
while(true)
{
synchronized(MyLock.LOCKB)
{
System.out.println(Thread.currentThread().getName()+"else......lockb");
synchronized(MyLock.LOCKA)
{
System.out.println(Thread.currentThread().getName()+"else......locka");
}
}
}
}
}
} //单独定义一个用于存储锁对象类。
class MyLock
{
public static final Object LOCKA = new Object();
public static final Object LOCKB = new Object();
}
class DeadLockTest
{
public static void main(String[] args)
{
//创建了两个线程任务。
Test t1 = new Test(true);
Test t2 = new Test(false); Thread t11 = new Thread(t1);
Thread t22 = new Thread(t2);
t11.start();
t22.start();
}
}
 //多线程间的通信-生产者&消费者-问题发生。
/*
多线程中最为常见的应用案例,
生产者消费者问题。
生产和消费同时执行,需要多线程。
但是执行的任务却不相同,处理的资源是相同的。线程间的通信。 1,描述资源。
2,描述生产者,因为具备着自己的任务。
3,描述消费者,因为具备着自己的任务。 问题1:
数据错误,已经被生产很早期的商品,才被消费到。
出现线程安全问题,需要用同步来解决。
问题已解决:不会再消费到之前很早期的商品。 问题2:
发现了连续生产却没有消费,同时对同一个商品进行多次消费。
希望的结果应该是生产一个商品,就被消费掉,生产下一个商品。 搞清楚机个问题:
生产者什么时候应该生产呢?
当盘子中没有面包,就生产,如果有了面包,就不要消费。 消费者什么时候应该消费呢?
当盘子中已有面包,就消费,如果没有面包,就不要消费。 */ //1,描述资源。属性:名称和编号。 行为:对商品名称赋值,获取商品
class Resource
{
private String name;
private int count=1; //1,提供设置的方法。
public synchronized void set(String name)
{
//1,给成员变量赋值并加上编号。
this.name = name+count;
count++; //2,打印生产了哪个商品。
System.out.println(Thread.currentThread().getName()+"....生产者..."+this.name); } public synchronized void out()
{
System.out.println(Thread.currentThread().getName()+"....消费者..."+this.name);
}
} //2,描述生产者。
class Producer implements Runnable
{
private Resource r ;
//生产者一初始化就要有资源。需要将资源传递到构造函数中。
Producer(Resource r)
{
this.r = r;
}
public void run()
{
while(true)
{
r.set("面包");
}
}
} //3,描述消费者。
class Consumer implements Runnable
{
private Resource r ;
//消费者一初始化就要有资源。需要将资源传递到构造函数中。
Consumer(Resource r)
{
this.r = r;
}
public void run()
{
while(true)
{
r.out();
}
}
} class ThreadDemo8
{
public static void main(String[] args)
{
//创建资源对象。
Resource r = new Resource(); //创建线程任务。
Producer pro = new Producer(r);
Consumer con = new Consumer(r); //3,创建线程。
Thread t1 = new Thread(pro);
Thread t2 = new Thread(con); t1.start();
t2.start();
}
}
 //多线程间的通信-生产者&消费者-问题发生。以及等待唤醒机制。
/*
多线程中最为常见的应用案例,
生产者消费者问题。
生产和消费同时执行,需要多线程。
但是执行的任务却不相同,处理的资源是相同的。线程间的通信。 1,描述资源。
2,描述生产者,因为具备着自己的任务。
3,描述消费者,因为具备着自己的任务。 问题1:
数据错误,已经被生产很早期的商品,才被消费到。
出现线程安全问题,需要用同步来解决。
问题已解决:不会再消费到之前很早期的商品。 问题2:
发现了连续生产却没有消费,同时对同一个商品进行多次消费。
希望的结果应该是生产一个商品,就被消费掉,生产下一个商品。 搞清楚机个问题:
生产者什么时候应该生产呢?
当盘子中没有面包,就生产,如果有了面包,就不要消费。 消费者什么时候应该消费呢?
当盘子中已有面包,就消费,如果没有面包,就不要消费。 生产者生产了商品后,应该去告诉消费者来消费。而这时的生产者应该处于等待状态。
消费者消费了商品后,应该告诉生产者去生产,而这时的消费者应该处于等待状态。 ======================================================
等待/唤醒机制。
wait();会让线程处于等待状态,其实就是将线程临时存储到了线程池中。
notify();会唤醒线程池中任意一个等待的线程。
notifyAll();会唤醒线程池中所有的等待线程。 记住:这些方法必须使用在同步中,必须要标识wait,notify等方法所属的锁。
同一个锁上的notify,只能唤醒该锁上的wait线程。 为什么这些方法定义在了Object中呢?
因为这些方法必须标识所属的锁。而锁可以是任意对象,任意对象可以调用的方法必然是Objec的方法。 距离:小朋友抓人游戏。
*/ //1,描述资源。属性:名称和编号。 行为:对商品名称赋值,获取商品
class Resource
{
private String name;
private int count=1; //定义标记。
private boolean flag = false; //1,提供设置的方法。
public synchronized void set(String name)
{
if(flag)
try{this.wait();}catch(InterruptedException e){}
//1,给成员变量赋值并加上编号。
this.name = name+count;
count++; //2,打印生产了哪个商品。
System.out.println(Thread.currentThread().getName()+"....生产者..."+this.name); //将标记该为true
flag = true;
//唤醒消费者。
this.notify(); } public synchronized void out()
{
if(!flag)
try{wait();}catch(InterruptedException e){}
System.out.println(Thread.currentThread().getName()+"....消费者..."+this.name);
//将标记该为flase。
flag = false;
//唤醒生产者。
notify();
}
} //2,描述生产者。
class Producer implements Runnable
{
private Resource r ;
//生产者一初始化就要有资源。需要将资源传递到构造函数中。
Producer(Resource r)
{
this.r = r;
}
public void run()
{
while(true)
{
r.set("面包");
}
}
} //3,描述消费者。
class Consumer implements Runnable
{
private Resource r ;
//消费者一初始化就要有资源。需要将资源传递到构造函数中。
Consumer(Resource r)
{
this.r = r;
}
public void run()
{
while(true)
{
r.out();
}
}
} class ThreadDemo9
{
public static void main(String[] args)
{
//创建资源对象。
Resource r = new Resource(); //创建线程任务。
Producer pro = new Producer(r);
Consumer con = new Consumer(r); //3,创建线程。
Thread t1 = new Thread(pro);
Thread t2 = new Thread(con); t1.start();
t2.start();
}
}
 //多生产&多消费问题发生及解决。
/*
java.util.concurrent.locks 软件包中提供了相应的解决方案。
Lock接口。比同步更厉害,有更多的操作,获取锁:lock(); 释放锁:unlock();
提供了一个更加面向对象的锁。在该锁中提供了更多的显示的锁操作。
可以替代同步。 升级到JDK1.5,先别同步改为Lock.
*/ /*
多生产多消费。
问题1:生产了商品没有被消费,同一个商品被消费多次。
Thread-2....生产者...面包285
Thread-0....生产者...面包286
Thread-1....消费者...面包286
Thread-2....生产者...面包287
Thread-0....生产者...面包288
Thread-1....消费者...面包288 被唤醒的线程没有判断标记,造成了问题1的产生。
解决:只要让被唤醒的线程必须判断标记就可以了。将if判断标记的方式改为while判断标记。
注意:只要是多生产,多消费,必须是while判断标记。 问题2:while判断后,死锁了。
原因:生产方唤醒了线程池中的生产方的线程。本方唤醒了本方。
解决:希望本方要唤醒对方。没有对应方法,只能唤醒所有。 其实还是有一些问题的。效率低了。
*/
//1,描述资源。属性:名称和编号。 行为:对商品名称赋值,获取商品
class Resource
{
private String name;
private int count=1; //定义一个锁对象。
private Lock lock = new ReentrantLock(); //定义标记。
private boolean flag = false; //1,提供设置的方法。
public synchronized void set(String name)// t1 t2
{
//if(flag)
while(flag)
try{this.wait();}catch(InterruptedException e){}
//1,给成员变量赋值并加上编号。
this.name = name+count;//商品1
count++;//2
//2,打印生产了哪个商品。
System.out.println(Thread.currentThread().getName()+"....生产者..."+this.name);//生产了商品1 //将标记该为true
flag = true;
//唤醒消费者。
this.notifyAll(); } public synchronized void out()// t3 t4
{
//if(!flag)
while(!flag)
try{wait();}catch(InterruptedException e){}
System.out.println(Thread.currentThread().getName()+"....消费者..."+this.name);
//将标记该为flase。
flag = false;
//唤醒生产者。
this.notifyAll();
}
} //2,描述生产者。
class Producer implements Runnable
{
private Resource r ;
//生产者一初始化就要有资源。需要将资源传递到构造函数中。
Producer(Resource r)
{
this.r = r;
}
public void run()
{
while(true)
{
r.set("面包");
}
}
} //3,描述消费者。
class Consumer implements Runnable
{
private Resource r ;
//消费者一初始化就要有资源。需要将资源传递到构造函数中。
Consumer(Resource r)
{
this.r = r;
}
public void run()
{
while(true)
{
r.out();
}
}
} class ThreadDemo10
{
public static void main(String[] args)
{
//创建资源对象。
Resource r = new Resource(); //创建线程任务。
Producer pro = new Producer(r);
Consumer con = new Consumer(r); //3,创建线程。
Thread t1 = new Thread(pro);
Thread t2 = new Thread(pro);
Thread t3 = new Thread(con);
Thread t4 = new Thread(con); t1.start();
t2.start();
t3.start();
t4.start();
}
}
 //多生产&多消费问题发生及解决。
import java.util.concurrent.locks.*;
/*
java.util.concurrent.locks 软件包中提供了相应的解决方案。
Lock接口。比同步更厉害,有更多的操作,获取锁:lock(); 释放锁:unlock();
提供了一个更加面向对象的锁。在该锁中提供了更多的显示的锁操作。
可以替代同步。 升级到JDK1.5,先别同步改为Lock.
已经将旧锁替换成新锁,那么所上的监视器方法(wait notify notifyAll )也应该替换
成新锁上的方法。
而JDK1.5中将这些原有的监视器方法封装到了一个Condition对象中。
想要获取监视器方法,需要先获取Condition对象。 Condition对象的出现其实就是替代了Object中的监视器方法。
await();
signal();
signalAll();
将所有的监视器方法替换成了Condition.
功能和ThreadDemo10.java的程序一样,仅仅是用新的对象,改了写法而已。
但是问题依旧,效率还是很低。
老程序中可以通过两个嵌套完成,但是容易引发死锁。 新程序中,就可以解决这个问题。
可以在一个锁上加上多个监视器对象。
*/
class Resource
{
private String name;
private int count=1; //定义一个锁对象。
private Lock lock = new ReentrantLock();
//获取锁上的Condition对象。为了解决本方唤醒对方的问题,可以一个锁上创建两个监视器对象。
private Condition produce = lock.newCondition();//负责生产的.
private Condition consume = lock.newCondition();//负责消费的. //定义标记。
private boolean flag = false; //1,提供设置的方法。
public void set(String name)// t1 t2
{
//获取锁。
lock.lock();
try{
while(flag)
try{produce.await();}catch(InterruptedException e){}
this.name = name+count;//商品1
count++;
System.out.println(Thread.currentThread().getName()+"....生产者..."+this.name);//生产了商品1 //将标记该为true
flag = true;
//执行消费者的唤醒。而且是唤醒一个消费者就行了。
consume.signal();
}
finally{
lock.unlock();//一定要执行。
}
} public void out()// t3 t4
{
lock.lock();
try{
while(!flag)
try{consume.await();}catch(InterruptedException e){}
System.out.println(Thread.currentThread().getName()+"....消费者..."+this.name);
//将标记该为flase。
flag = false;
produce.signal();
}
finally{
lock.unlock();
}
}
} //2,描述生产者。
class Producer implements Runnable
{
private Resource r ;
//生产者一初始化就要有资源。需要将资源传递到构造函数中。
Producer(Resource r)
{
this.r = r;
}
public void run()
{
while(true)
{
r.set("面包");
}
}
} //3,描述消费者。
class Consumer implements Runnable
{
private Resource r ;
//消费者一初始化就要有资源。需要将资源传递到构造函数中。
Consumer(Resource r)
{
this.r = r;
}
public void run()
{
while(true)
{
r.out();
}
}
} class ThreadDemo11
{
public static void main(String[] args)
{
//创建资源对象。
Resource r = new Resource(); //创建线程任务。
Producer pro = new Producer(r);
Consumer con = new Consumer(r); //3,创建线程。
Thread t1 = new Thread(pro);
Thread t2 = new Thread(pro);
Thread t3 = new Thread(con);
Thread t4 = new Thread(con); t1.start();
t2.start();
t3.start();
t4.start();
}
}
 //接口 Condition示例:
class BoundedBuffer {
final Lock lock = new ReentrantLock();//锁
final Condition notFull = lock.newCondition(); //生产。
final Condition notEmpty = lock.newCondition(); //消费。 final Object[] items = new Object[100];//存储商品的容器。
int putptr/*生产者使用的脚标*/, takeptr,/*消费者使用的角标*/ count;//计数器。 /*生产者使用的方法,往数组中存储商品。*/
public void put(Object x) throws InterruptedException {
lock.lock();
try {
while (count == items.length) //判断计数器是否已到数据长度。慢了。
notFull.await();//生产者等待。 items[putptr] = x; //安照角标将商品存储到数组中。 if (++putptr == items.length)//如果存储的角标到了数组的长度,就将角标归零。
putptr = 0;
++count;//计数器自增。
notEmpty.signal();//唤醒一个消费者。
} finally {
lock.unlock();
}
} public Object take() throws InterruptedException {
lock.lock();
try {
while (count == 0) //如果计数器为零,说明没有商品,消费者需要等待。
notEmpty.await();
Object x = items[takeptr]; //从数组中通过消费者角标获取商品。 if (++takeptr == items.length) //如果消费者角标等于数组长度,将角标归零。
takeptr = 0;
--count;//计数器自增。
notFull.signal();//唤醒生产者。
return x;
} finally {
lock.unlock();
}
}
}

《day15---多线程安全问题_JDK1.5的锁机制》的更多相关文章

  1. 简单物联网:外网访问内网路由器下树莓派Flask服务器

    最近做一个小东西,大概过程就是想在教室,宿舍控制实验室的一些设备. 已经在树莓上搭了一个轻量的flask服务器,在实验室的路由器下,任何设备都是可以访问的:但是有一些限制条件,比如我想在宿舍控制我种花 ...

  2. 利用ssh反向代理以及autossh实现从外网连接内网服务器

    前言 最近遇到这样一个问题,我在实验室架设了一台服务器,给师弟或者小伙伴练习Linux用,然后平时在实验室这边直接连接是没有问题的,都是内网嘛.但是回到宿舍问题出来了,使用校园网的童鞋还是能连接上,使 ...

  3. 外网访问内网Docker容器

    外网访问内网Docker容器 本地安装了Docker容器,只能在局域网内访问,怎样从外网也能访问本地Docker容器? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Docker容器 ...

  4. 外网访问内网SpringBoot

    外网访问内网SpringBoot 本地安装了SpringBoot,只能在局域网内访问,怎样从外网也能访问本地SpringBoot? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装Java 1 ...

  5. 外网访问内网Elasticsearch WEB

    外网访问内网Elasticsearch WEB 本地安装了Elasticsearch,只能在局域网内访问其WEB,怎样从外网也能访问本地Elasticsearch? 本文将介绍具体的实现步骤. 1. ...

  6. 怎样从外网访问内网Rails

    外网访问内网Rails 本地安装了Rails,只能在局域网内访问,怎样从外网也能访问本地Rails? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Rails 默认安装的Rails端口 ...

  7. 怎样从外网访问内网Memcached数据库

    外网访问内网Memcached数据库 本地安装了Memcached数据库,只能在局域网内访问,怎样从外网也能访问本地Memcached数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装 ...

  8. 怎样从外网访问内网CouchDB数据库

    外网访问内网CouchDB数据库 本地安装了CouchDB数据库,只能在局域网内访问,怎样从外网也能访问本地CouchDB数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Cou ...

  9. 怎样从外网访问内网DB2数据库

    外网访问内网DB2数据库 本地安装了DB2数据库,只能在局域网内访问,怎样从外网也能访问本地DB2数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动DB2数据库 默认安装的DB2 ...

  10. 怎样从外网访问内网OpenLDAP数据库

    外网访问内网OpenLDAP数据库 本地安装了OpenLDAP数据库,只能在局域网内访问,怎样从外网也能访问本地OpenLDAP数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动 ...

随机推荐

  1. java,UDP协议简单实现

    //UDP协议简单实现-----Serverpackage UDP; import java.net.DatagramPacket; import java.net.DatagramSocket; i ...

  2. 解决由于一个软件限制策略的阻止,windows无法运行此程序cmd.reg

    解决由于一个软件限制策略的阻止,windows无法运行此程序cmd.reg Windows Registry Editor Version 5.00 [-HKEY_LOCAL_MACHINE\SOFT ...

  3. python2 httplib 笔记

    python2  httplib 笔记 #coding=utf-8 ''' Created on 2014年9月25日 @author: cocoajin ''' import httplib,url ...

  4. mac svn

    开启svn服务:sudo svnserve -d -r /Users/fuyi/svnserver/mycode/

  5. 《javascript高级程序设计》第四章 Variables,scope,and memory

    4.1 基本类型和引用类型的值 primitive and reference values 4.1.1 动态的属性 dynamic properties 4.1.2 复制变量值 copying va ...

  6. javaNIO学习

    Buffer其实就是是一个容器对象,它包含一些要写入或者刚读出的数据.在NIO中加入Buffer对象,体现了新库与原I/O的一个重要区别.在面向流的I/O中,您将数据直接写入或者将数据直接读到Stre ...

  7. poj---(2886)Who Gets the Most Candies?(线段树+数论)

    Who Gets the Most Candies? Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 10373   Acc ...

  8. DB、ETL、DW、OLAP、DM、BI关系结构图

    DB.ETL.DW.OLAP.DM.BI关系结构图 在此大概用口水话简单叙述一下他们几个概念: (1)DB/Database/数据库——这里一般指的就是OLTP数据库,在线事物数据库,用来支持生产的, ...

  9. SQL Server数据库(作业)

    create datebase zuoye2gouse zuoyegocreate table student --学生表( Sno varchar(20) not null primary key, ...

  10. SQL Server数据库(表的创建)

    表的创建 1.创建列(字段):列名+类型 2.设置主键列:能够唯一表示一条数据 3.设置唯一键:设计--索引/键--添加--唯一键(选择列)--确定 唯一键的内容不能重复 4.外键关系:一张表(从表) ...